From 7f88aedbc3b53496bc99d8e0e64a818c7a3f6d6f Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Fri, 24 Jan 2025 00:26:00 +0100 Subject: [PATCH 001/145] #3423 Add Lua as Compile Target in Viewer Script Editor --- indra/llmessage/message_prehash.cpp | 2 + indra/llmessage/message_prehash.h | 2 + indra/llui/llcombobox.cpp | 17 +- indra/llui/llcombobox.h | 5 +- indra/llui/llscrolllistctrl.cpp | 13 + indra/llui/llscrolllistctrl.h | 3 +- indra/newview/llcompilequeue.cpp | 22 +- indra/newview/llcompilequeue.h | 11 +- indra/newview/llpreviewscript.cpp | 189 +++++++------- indra/newview/llpreviewscript.h | 33 ++- indra/newview/llstartup.cpp | 244 ++++++++---------- indra/newview/llviewerassetupload.cpp | 8 +- indra/newview/llviewerassetupload.h | 12 +- indra/newview/llviewermenu.cpp | 6 +- .../default/xui/en/floater_live_lsleditor.xml | 74 +++--- 15 files changed, 324 insertions(+), 317 deletions(-) diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index c264a9f0860..df16184e765 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -714,6 +714,8 @@ char const* const _PREHASH_FirstName = LLMessageStringTable::getInstance()->getS char const* const _PREHASH_AttachedSoundGainChange = LLMessageStringTable::getInstance()->getString("AttachedSoundGainChange"); char const* const _PREHASH_LocationID = LLMessageStringTable::getInstance()->getString("LocationID"); char const* const _PREHASH_Running = LLMessageStringTable::getInstance()->getString("Running"); +char const* const _PREHASH_Mono = LLMessageStringTable::getInstance()->getString("Mono"); +char const* const _PREHASH_CompileTarget = LLMessageStringTable::getInstance()->getString("CompileTarget"); char const* const _PREHASH_AgentThrottle = LLMessageStringTable::getInstance()->getString("AgentThrottle"); char const* const _PREHASH_NeighborList = LLMessageStringTable::getInstance()->getString("NeighborList"); char const* const _PREHASH_PathTaperX = LLMessageStringTable::getInstance()->getString("PathTaperX"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index 1d30b69b675..0feb6ecad8a 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -714,6 +714,8 @@ extern char const* const _PREHASH_FirstName; extern char const* const _PREHASH_AttachedSoundGainChange; extern char const* const _PREHASH_LocationID; extern char const* const _PREHASH_Running; +extern char const* const _PREHASH_Mono; +extern char const* const _PREHASH_CompileTarget; extern char const* const _PREHASH_AgentThrottle; extern char const* const _PREHASH_NeighborList; extern char const* const _PREHASH_PathTaperX; diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index f3876ef6957..17e583b868c 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -251,11 +251,26 @@ void LLComboBox::resetDirty() } } -bool LLComboBox::itemExists(const std::string& name) +bool LLComboBox::itemExists(const std::string& name) const { return mList->getItemByLabel(name); } +bool LLComboBox::valueExists(const std::string& value) const +{ + return mList->getItemByValue(value); +} + +LLScrollListItem* LLComboBox::findItemByValue(const std::string& value) const +{ + return mList->getItemByValue(value); +} + +std::vector LLComboBox::getAllData() const +{ + return mList->getAllData(); +} + // add item "name" to menu LLScrollListItem* LLComboBox::add(const std::string& name, EAddPosition pos, bool enabled) { diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 8be3eb57e4f..be18cdba487 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -143,7 +143,10 @@ class LLComboBox LLScrollListItem* addSeparator(EAddPosition pos = ADD_BOTTOM); bool remove( S32 index ); // remove item by index, return true if found and removed void removeall() { clearRows(); } - bool itemExists(const std::string& name); + bool itemExists(const std::string& name) const; + bool valueExists(const std::string& value) const; + LLScrollListItem* findItemByValue(const std::string& value) const; + std::vector getAllData() const; void sortByName(bool ascending = true); // Sort the entries in the combobox by name diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 93bd3c6bedb..deaf2fe1887 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1281,6 +1281,19 @@ LLScrollListItem* LLScrollListCtrl::getItemByLabel(const std::string& label, boo return NULL; } +LLScrollListItem* LLScrollListCtrl::getItemByValue(const std::string& value) +{ + for (LLScrollListItem* item : mItemList) + { + if (item->getValue().asString() == value) + { + return item; + } + } + + return NULL; +} + LLScrollListItem* LLScrollListCtrl::getItemByIndex(S32 index) { if (index >= 0 && index < (S32)mItemList.size()) diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index c24784338aa..70d4a75fb51 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -263,7 +263,8 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, bool selectItemByLabel(const std::string& item, bool case_sensitive = true, S32 column = 0); // false if item not found bool selectItemByPrefix(const std::string& target, bool case_sensitive = true, S32 column = -1); bool selectItemByPrefix(const LLWString& target, bool case_sensitive = true, S32 column = -1); - LLScrollListItem* getItemByLabel(const std::string& item, bool case_sensitive = true, S32 column = 0); + LLScrollListItem* getItemByLabel(const std::string& label, bool case_sensitive = true, S32 column = 0); + LLScrollListItem* getItemByValue(const std::string& value); LLScrollListItem* getItemByIndex(S32 index); std::string getSelectedItemLabel(S32 column = 0) const; LLSD getSelectedValue(); diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index 552ea75559a..32d0f3fa1b4 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -122,9 +122,9 @@ namespace class LLQueuedScriptAssetUpload : public LLScriptAssetUpload { public: - LLQueuedScriptAssetUpload(LLUUID taskId, LLUUID itemId, LLUUID assetId, TargetType_t targetType, + LLQueuedScriptAssetUpload(LLUUID taskId, LLUUID itemId, LLUUID assetId, std::string compileTarget, bool isRunning, std::string scriptName, LLUUID queueId, LLUUID exerienceId, taskUploadFinish_f finish) : - LLScriptAssetUpload(taskId, itemId, targetType, isRunning, + LLScriptAssetUpload(taskId, itemId, compileTarget, isRunning, exerienceId, std::string(), finish, nullptr), mScriptName(scriptName), mQueueId(queueId) @@ -183,9 +183,7 @@ struct LLScriptQueueData // Default constructor LLFloaterScriptQueue::LLFloaterScriptQueue(const LLSD& key) : - LLFloater(key), - mDone(false), - mMono(false) + LLFloater(key) { } @@ -197,7 +195,7 @@ LLFloaterScriptQueue::~LLFloaterScriptQueue() bool LLFloaterScriptQueue::postBuild() { - childSetAction("close",onCloseBtn,this); + childSetAction("close", onCloseBtn, this); getChildView("close")->setEnabled(false); setVisible(true); return true; @@ -222,8 +220,8 @@ bool LLFloaterScriptQueue::start() LLStringUtil::format_map_t args; args["[START]"] = mStartString; - args["[COUNT]"] = llformat ("%d", mObjectList.size()); - buffer = getString ("Starting", args); + args["[COUNT]"] = llformat("%d", mObjectList.size()); + buffer = getString("Starting", args); getChild("queue output")->addSimpleElement(buffer, ADD_BOTTOM); @@ -276,8 +274,8 @@ bool LLFloaterCompileQueue::hasExperience( const LLUUID& id ) const return mExperienceIds.find(id) != mExperienceIds.end(); } -// //Attempt to record this asset ID. If it can not be inserted into the set -// //then it has already been processed so return false. +// Attempt to record this asset ID. If it can not be inserted into the set +// then it has already been processed so return false. void LLFloaterCompileQueue::handleHTTPResponse(std::string pumpName, const LLSD &expresult) { @@ -359,7 +357,7 @@ bool LLFloaterCompileQueue::processScript(LLHandle hfloat LLCheckedHandle floater(hfloater); // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle. // which is caught in objectScriptProcessingQueueCoro - bool monocompile = floater->mMono; + std::string compile_target = floater->mCompileTarget; // Initial test to see if we can (or should) attempt to compile the script. LLInventoryItem *item = dynamic_cast(inventory); @@ -470,7 +468,7 @@ bool LLFloaterCompileQueue::processScript(LLHandle hfloat LLResourceUploadInfo::ptr_t uploadInfo(new LLQueuedScriptAssetUpload(object->getID(), inventory->getUUID(), assetId, - monocompile ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2, + compile_target, true, inventory->getName(), LLUUID(), diff --git a/indra/newview/llcompilequeue.h b/indra/newview/llcompilequeue.h index 951d4800e8c..42af5b18812 100644 --- a/indra/newview/llcompilequeue.h +++ b/indra/newview/llcompilequeue.h @@ -55,7 +55,7 @@ class LLFloaterScriptQueue : public LLFloater/*, public LLVOInventoryListener*/ /*virtual*/ bool postBuild(); - void setMono(bool mono) { mMono = mono; } + void setCompileTarget(std::string target) { mCompileTarget = target; } // addObject() accepts an object id. void addObject(const LLUUID& id, std::string name); @@ -80,8 +80,8 @@ class LLFloaterScriptQueue : public LLFloater/*, public LLVOInventoryListener*/ protected: // UI - LLScrollListCtrl* mMessages; - LLButton* mCloseBtn; + LLScrollListCtrl* mMessages { nullptr }; + LLButton* mCloseBtn { nullptr }; // Object Queue struct ObjectData @@ -93,14 +93,13 @@ class LLFloaterScriptQueue : public LLFloater/*, public LLVOInventoryListener*/ object_data_list_t mObjectList; LLUUID mCurrentObjectID; - bool mDone; + bool mDone { false }; std::string mStartString; - bool mMono; + std::string mCompileTarget { "lsl2" }; typedef boost::function &, LLInventoryObject*, LLEventPump &)> fnQueueAction_t; static void objectScriptProcessingQueueCoro(std::string action, LLHandle hfloater, object_data_list_t objectList, fnQueueAction_t func); - }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 02a4c7fb267..432aaa8f184 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -441,42 +441,37 @@ void LLLiveLSLEditor::experienceChanged() } } -void LLLiveLSLEditor::onViewProfile( LLUICtrl *ui, void* userdata ) +void LLLiveLSLEditor::onViewProfile() { - LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; - - LLUUID id; - if(self->mExperienceEnabled->get()) + if (mExperienceEnabled->get()) { - id=self->mScriptEd->getAssociatedExperience(); - if(id.notNull()) + LLUUID id = mScriptEd->getAssociatedExperience(); + if (id.notNull()) { LLFloaterReg::showInstance("experience_profile", id, true); } } - } -void LLLiveLSLEditor::onToggleExperience( LLUICtrl *ui, void* userdata ) +void LLLiveLSLEditor::onToggleExperience() { - LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; - LLUUID id; - if(self->mExperienceEnabled->get()) + if (mExperienceEnabled->get()) { - if(self->mScriptEd->getAssociatedExperience().isNull()) + if (mScriptEd->getAssociatedExperience().isNull()) { - id=self->mExperienceIds.beginArray()->asUUID(); + id = mExperienceIds.beginArray()->asUUID(); } } - if(id != self->mScriptEd->getAssociatedExperience()) + if (id != mScriptEd->getAssociatedExperience()) { - self->mScriptEd->enableSave(self->getIsModifiable()); + mScriptEd->enableSave(getIsModifiable()); } - self->mScriptEd->setAssociatedExperience(id); - self->updateExperiencePanel(); + mScriptEd->setAssociatedExperience(id); + + updateExperiencePanel(); } bool LLScriptEdCore::postBuild() @@ -1375,7 +1370,7 @@ void LLLiveLSLEditor::updateExperiencePanel() mExperienceEnabled->setEnabled(false); mExperienceEnabled->setToolTip(getString("no_experiences")); } - getChild("view_profile")->setVisible(false); + mViewProfileButton->setVisible(false); } else { @@ -1383,7 +1378,7 @@ void LLLiveLSLEditor::updateExperiencePanel() mExperienceEnabled->setEnabled(getIsModifiable()); mExperiences->setVisible(true); mExperienceEnabled->set(true); - getChild("view_profile")->setToolTip(getString("show_experience_profile")); + mViewProfileButton->setToolTip(getString("show_experience_profile")); buildExperienceList(); } } @@ -1452,7 +1447,7 @@ void LLLiveLSLEditor::buildExperienceList() mExperiences->setEnabled(true); mExperiences->sortByName(true); mExperiences->setCurrentByIndex(mExperiences->getCurrentIndex()); - getChild("view_profile")->setVisible(true); + mViewProfileButton->setVisible(true); } } @@ -1960,28 +1955,26 @@ LLLiveLSLEditor::LLLiveLSLEditor(const LLSD& key) : bool LLLiveLSLEditor::postBuild() { - childSetCommitCallback("running", LLLiveLSLEditor::onRunningCheckboxClicked, this); - getChildView("running")->setEnabled(false); + mResetButton = getChild("reset"); + mResetButton->setClickedCallback([&](LLUICtrl*, const LLSD&) { onReset(); }); - childSetAction("Reset",&LLLiveLSLEditor::onReset,this); - getChildView("Reset")->setEnabled(true); - - mMonoCheckbox = getChild("mono"); - childSetCommitCallback("mono", &LLLiveLSLEditor::onMonoCheckboxClicked, this); - getChildView("mono")->setEnabled(true); - - mScriptEd->mEditor->makePristine(); - mScriptEd->mEditor->setFocus(true); + mRunningCheckbox = getChild("running"); + mRunningCheckbox->setCommitCallback([&](LLUICtrl*, const LLSD&) { onRunningCheckboxClicked(); }); + mCompileTarget = getChild("compile_target"); + mCompileTarget->setCommitCallback([&](LLUICtrl*, const LLSD&) { onCompileTargetChanged(); }); mExperiences = getChild("Experiences..."); - mExperiences->setCommitCallback(boost::bind(&LLLiveLSLEditor::experienceChanged, this)); + mExperiences->setCommitCallback([&](LLUICtrl*, const LLSD&) { experienceChanged(); }); mExperienceEnabled = getChild("enable_xp"); + mExperienceEnabled->setCommitCallback([&](LLUICtrl*, const LLSD&) { onToggleExperience(); }); - childSetCommitCallback("enable_xp", onToggleExperience, this); - childSetCommitCallback("view_profile", onViewProfile, this); + mViewProfileButton = getChild("view_profile"); + mViewProfileButton->setClickedCallback([&](LLUICtrl*, const LLSD&) { onViewProfile(); }); + mScriptEd->mEditor->makePristine(); + mScriptEd->mEditor->setFocus(true); return LLPreview::postBuild(); } @@ -1994,7 +1987,7 @@ void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id, LL_DEBUGS() << "LSL Bytecode saved" << LL_ENDL; mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessful")); mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete")); - getChild("running")->set(is_script_running); + mRunningCheckbox->set(is_script_running); mIsSaving = false; closeIfNeeded(); } @@ -2057,9 +2050,10 @@ void LLLiveLSLEditor::loadAsset() { mItem = new LLViewerInventoryItem(item); // request the text from the object - LLSD* user_data = new LLSD(); - user_data->with("taskid", mObjectUUID).with("itemid", mItemUUID); - gAssetStorage->getInvItemAsset(object->getRegion()->getHost(), + LLSD* user_data = new LLSD(); + user_data->with("taskid", mObjectUUID).with("itemid", mItemUUID); + gAssetStorage->getInvItemAsset( + object->getRegion()->getHost(), gAgent.getID(), gAgent.getSessionID(), item->getPermissions().getOwner(), @@ -2067,8 +2061,8 @@ void LLLiveLSLEditor::loadAsset() item->getUUID(), item->getAssetUUID(), item->getType(), - &LLLiveLSLEditor::onLoadComplete, - (void*)user_data, + LLLiveLSLEditor::onLoadComplete, + user_data, true); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_GetScriptRunning); @@ -2202,14 +2196,9 @@ void LLLiveLSLEditor::loadScriptText(const LLUUID &uuid, LLAssetType::EType type } -void LLLiveLSLEditor::onRunningCheckboxClicked( LLUICtrl*, void* userdata ) +void LLLiveLSLEditor::onRunningCheckboxClicked() { - LLLiveLSLEditor* self = (LLLiveLSLEditor*) userdata; - LLViewerObject* object = gObjectList.findObject( self->mObjectUUID ); - LLCheckBoxCtrl* runningCheckbox = self->getChild("running"); - bool running = runningCheckbox->get(); - //self->mRunningCheckbox->get(); - if( object ) + if (LLViewerObject* object = gObjectList.findObject(mObjectUUID)) { LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_SetScriptRunning); @@ -2217,24 +2206,21 @@ void LLLiveLSLEditor::onRunningCheckboxClicked( LLUICtrl*, void* userdata ) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, self->mObjectUUID); - msg->addUUIDFast(_PREHASH_ItemID, self->mItemUUID); - msg->addBOOLFast(_PREHASH_Running, running); + msg->addUUIDFast(_PREHASH_ObjectID, mObjectUUID); + msg->addUUIDFast(_PREHASH_ItemID, mItemUUID); + msg->addBOOLFast(_PREHASH_Running, mRunningCheckbox->get()); msg->sendReliable(object->getRegion()->getHost()); } else { - runningCheckbox->set(!running); + mRunningCheckbox->set(!mRunningCheckbox->get()); LLNotificationsUtil::add("CouldNotStartStopScript"); } } -void LLLiveLSLEditor::onReset(void *userdata) +void LLLiveLSLEditor::onReset() { - LLLiveLSLEditor* self = (LLLiveLSLEditor*) userdata; - - LLViewerObject* object = gObjectList.findObject( self->mObjectUUID ); - if(object) + if (LLViewerObject* object = gObjectList.findObject(mObjectUUID)) { LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ScriptReset); @@ -2242,8 +2228,8 @@ void LLLiveLSLEditor::onReset(void *userdata) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, self->mObjectUUID); - msg->addUUIDFast(_PREHASH_ItemID, self->mItemUUID); + msg->addUUIDFast(_PREHASH_ObjectID, mObjectUUID); + msg->addUUIDFast(_PREHASH_ItemID, mItemUUID); msg->sendReliable(object->getRegion()->getHost()); } else @@ -2255,34 +2241,33 @@ void LLLiveLSLEditor::onReset(void *userdata) void LLLiveLSLEditor::draw() { LLViewerObject* object = gObjectList.findObject(mObjectUUID); - LLCheckBoxCtrl* runningCheckbox = getChild( "running"); - if(object && mAskedForRunningInfo && mHaveRunningInfo) + if (object && mAskedForRunningInfo && mHaveRunningInfo) { - if(object->permAnyOwner()) + if (object->permAnyOwner()) { - runningCheckbox->setLabel(getString("script_running")); - runningCheckbox->setEnabled(!mIsSaving); + mRunningCheckbox->setLabel(getString("script_running")); + mRunningCheckbox->setEnabled(!mIsSaving); } else { - runningCheckbox->setLabel(getString("public_objects_can_not_run")); - runningCheckbox->setEnabled(false); + mRunningCheckbox->setLabel(getString("public_objects_can_not_run")); + mRunningCheckbox->setEnabled(false); // *FIX: Set it to false so that the ui is correct for // a box that is released to public. It could be // incorrect after a release/claim cycle, but will be // correct after clicking on it. - runningCheckbox->set(false); - mMonoCheckbox->set(false); + mRunningCheckbox->set(false); + mCompileTarget->clear(); } } - else if(!object) + else if (!object) { // HACK: Display this information in the title bar. // Really ought to put in main window. setTitle(LLTrans::getString("ObjectOutOfRange")); - runningCheckbox->setEnabled(false); - mMonoCheckbox->setEnabled(false); + mRunningCheckbox->setEnabled(false); + mCompileTarget->setEnabled(false); // object may have fallen out of range. mHaveRunningInfo = false; } @@ -2389,7 +2374,7 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) mScriptEd->sync(); } - bool isRunning = getChild("running")->get(); + bool is_running = mRunningCheckbox->get(); getWindow()->incBusyCount(); mPendingUploads++; @@ -2397,17 +2382,18 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) if (!url.empty()) { + std::string compile_target(mCompileTarget->getValue()); std::string buffer(mScriptEd->mEditor->getText()); LLUUID old_asset_id = mScriptEd->getAssetID(); LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared(mObjectUUID, mItemUUID, - monoChecked() ? LLScriptAssetUpload::MONO : LLScriptAssetUpload::LSL2, - isRunning, mScriptEd->getAssociatedExperience(), buffer, - [isRunning, old_asset_id](LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response) { - LLFileSystem::removeFile(old_asset_id, LLAssetType::AT_LSL_TEXT); - LLLiveLSLEditor::finishLSLUpload(itemId, taskId, newAssetId, response, isRunning); - }, - nullptr)); // needs failure handling? + compile_target, is_running, mScriptEd->getAssociatedExperience(), buffer, + [is_running, old_asset_id](LLUUID item_id, LLUUID task_id, LLUUID new_asset_id, LLSD response) + { + LLFileSystem::removeFile(old_asset_id, LLAssetType::AT_LSL_TEXT); + LLLiveLSLEditor::finishLSLUpload(item_id, task_id, new_asset_id, response, is_running); + }, + nullptr)); // needs failure handling? LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo); } @@ -2460,28 +2446,41 @@ void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**) if (LLLiveLSLEditor* instance = LLFloaterReg::findTypedInstance("preview_scriptedit", floater_key)) { instance->mHaveRunningInfo = true; + bool running; msg->getBOOLFast(_PREHASH_Script, _PREHASH_Running, running); - LLCheckBoxCtrl* runningCheckbox = instance->getChild("running"); - runningCheckbox->set(running); - bool mono; - msg->getBOOLFast(_PREHASH_Script, "Mono", mono); - LLCheckBoxCtrl* monoCheckbox = instance->getChild("mono"); - monoCheckbox->setEnabled(instance->getIsModifiable() && have_script_upload_cap(object_id)); - monoCheckbox->set(mono); - } -} + instance->mRunningCheckbox->set(running); -void LLLiveLSLEditor::onMonoCheckboxClicked(LLUICtrl*, void* userdata) -{ - LLLiveLSLEditor* self = static_cast(userdata); - self->mMonoCheckbox->setEnabled(have_script_upload_cap(self->mObjectUUID)); - self->mScriptEd->enableSave(self->getIsModifiable()); + std::string compile_target; + msg->getStringFast(_PREHASH_Script, _PREHASH_CompileTarget, compile_target); + if (compile_target.empty()) // Old sim not providing CompileTarget field + { + bool mono; + msg->getBOOLFast(_PREHASH_Script, _PREHASH_Mono, mono); // Use Mono field + instance->mCompileTarget->setValue(mono ? "mono" : "lso2"); + } + else if (instance->mCompileTarget->valueExists(compile_target)) + { + instance->mCompileTarget->setValue(compile_target); // Use CompileTarget field + } + else + { + instance->mCompileTarget->setValue("mono"); // Use default value + } + + if (LLScrollListItem* item = instance->mCompileTarget->findItemByValue("luau")) + { + item->setEnabled(!compile_target.empty()); + } + + instance->mCompileTarget->setEnabled(instance->getIsModifiable() && have_script_upload_cap(object_id)); + } } -bool LLLiveLSLEditor::monoChecked() const +void LLLiveLSLEditor::onCompileTargetChanged() { - return mMonoCheckbox && mMonoCheckbox->getValue(); + mCompileTarget->setEnabled(have_script_upload_cap(mObjectUUID)); + mScriptEd->enableSave(getIsModifiable()); } void LLLiveLSLEditor::setAssociatedExperience( LLHandle editor, const LLSD& experience ) diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 70ee1a42746..9ec439d21ae 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -290,8 +290,8 @@ class LLLiveLSLEditor : public LLScriptEdContainer void setIsNew() { mIsNew = true; } static void setAssociatedExperience( LLHandle editor, const LLSD& experience ); - static void onToggleExperience(LLUICtrl *ui, void* userdata); - static void onViewProfile(LLUICtrl *ui, void* userdata); + void onToggleExperience(); + void onViewProfile(); void setExperienceIds(const LLSD& experience_ids); void buildExperienceList(); @@ -301,6 +301,8 @@ class LLLiveLSLEditor : public LLScriptEdContainer void setObjectName(std::string name) { mObjectName = name; } + bool getIsModifiable() const { return mIsModifiable; } // Evaluated on load assert + private: virtual bool canClose(); void closeIfNeeded(); @@ -308,8 +310,6 @@ class LLLiveLSLEditor : public LLScriptEdContainer virtual void loadAsset(); /*virtual*/ void saveIfNeeded(bool sync = true); - bool monoChecked() const; - static void onSearchReplace(void* userdata); static void onLoad(void* userdata); @@ -318,14 +318,14 @@ class LLLiveLSLEditor : public LLScriptEdContainer static void onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); - static void onRunningCheckboxClicked(LLUICtrl*, void* userdata); - static void onReset(void* userdata); + void onRunningCheckboxClicked(); + void onReset(); void loadScriptText(const LLUUID &uuid, LLAssetType::EType type); static void* createScriptEdPanel(void* userdata); - static void onMonoCheckboxClicked(LLUICtrl*, void* userdata); + void onCompileTargetChanged(); static void finishLSLUpload(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, bool isRunning); static void receiveExperienceIds(LLSD result, LLHandle parent); @@ -343,19 +343,18 @@ class LLLiveLSLEditor : public LLScriptEdContainer S32 mPendingUploads; bool mIsSaving; + bool mIsModifiable; - bool getIsModifiable() const { return mIsModifiable; } // Evaluated on load assert - - LLCheckBoxCtrl* mMonoCheckbox; - bool mIsModifiable; - - - LLComboBox* mExperiences; - LLCheckBoxCtrl* mExperienceEnabled; - LLSD mExperienceIds; + LLButton* mResetButton { nullptr }; + LLCheckBoxCtrl* mRunningCheckbox { nullptr }; + LLComboBox* mCompileTarget { nullptr }; + LLComboBox* mExperiences { nullptr }; + LLCheckBoxCtrl* mExperienceEnabled { nullptr }; + LLButton* mViewProfileButton { nullptr }; + LLSD mExperienceIds; LLHandle mExperienceProfile; - std::string mObjectName; + std::string mObjectName; }; #endif // LL_LLPREVIEWSCRIPT_H diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index b32b80331ab..322476f24a2 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2625,172 +2625,138 @@ void use_circuit_callback(void**, S32 result) void register_viewer_callbacks(LLMessageSystem* msg) { - msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data ); - msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update ); - msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update ); - msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update ); + msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data); + msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update); + msg->setHandlerFuncFast(_PREHASH_ObjectUpdateCompressed, process_compressed_object_update); + msg->setHandlerFuncFast(_PREHASH_ObjectUpdateCached, process_cached_object_update); msg->setHandlerFuncFast(_PREHASH_ImprovedTerseObjectUpdate, process_terse_object_update_improved ); - msg->setHandlerFunc("SimStats", process_sim_stats); - msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message ); + msg->setHandlerFuncFast(_PREHASH_SimStats, process_sim_stats); + msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message); msg->setHandlerFuncFast(_PREHASH_EconomyData, process_economy_data); - msg->setHandlerFunc("RegionInfo", LLViewerRegion::processRegionInfo); + msg->setHandlerFuncFast(_PREHASH_RegionInfo, LLViewerRegion::processRegionInfo); - msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator); - msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object, NULL); - msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage, process_time_synch, NULL); + msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator); + msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object); + msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage,process_time_synch); msg->setHandlerFuncFast(_PREHASH_EnableSimulator, process_enable_simulator); msg->setHandlerFuncFast(_PREHASH_DisableSimulator, process_disable_simulator); - msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user, NULL); - - msg->setHandlerFunc("CrossedRegion", process_crossed_region); - msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish); - - msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message); - msg->setHandlerFunc("AgentAlertMessage", process_agent_alert_message); - msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message, NULL); - msg->setHandlerFunc("ViewerFrozenMessage", process_frozen_message); - - msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value); - msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); - msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); - msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation); - msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); - msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); - msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); - msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); - msg->setHandlerFunc("ClearFollowCamProperties", process_clear_follow_cam_properties); + msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user); + + msg->setHandlerFuncFast(_PREHASH_CrossedRegion, process_crossed_region); + msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish); + + msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message); + msg->setHandlerFuncFast(_PREHASH_AgentAlertMessage, process_agent_alert_message); + msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message); + msg->setHandlerFuncFast(_PREHASH_ViewerFrozenMessage, process_frozen_message); + + msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value); + msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); + msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); + msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation); + msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); + msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); + msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); + msg->setHandlerFuncFast(_PREHASH_SetFollowCamProperties, process_set_follow_cam_properties); + msg->setHandlerFuncFast(_PREHASH_ClearFollowCamProperties, process_clear_follow_cam_properties); msg->setHandlerFuncFast(_PREHASH_ImprovedInstantMessage, process_improved_im); msg->setHandlerFuncFast(_PREHASH_ScriptQuestion, process_script_question); - msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL); - msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily, NULL); - msg->setHandlerFunc("ForceObjectSelect", LLSelectMgr::processForceObjectSelect); - - msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply, NULL); - msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL); - msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL); - msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL); - msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply, - &LLLiveLSLEditor::processScriptRunningReply); - - msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack); - - msg->setHandlerFunc("LogoutReply", process_logout_reply); - - //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility, - // &LLAgent::processAddModifyAbility); - //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility, - // &LLAgent::processRemoveModifyAbility); - msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate, - &LLAgent::processAgentDataUpdate); - msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate, - &LLAgent::processAgentGroupDataUpdate); - msg->setHandlerFunc("AgentDropGroup", - &LLAgent::processAgentDropGroup); - // land ownership messages - msg->setHandlerFuncFast(_PREHASH_ParcelOverlay, - LLViewerParcelMgr::processParcelOverlay); - msg->setHandlerFuncFast(_PREHASH_ParcelProperties, - LLViewerParcelMgr::processParcelProperties); - msg->setHandlerFunc("ParcelAccessListReply", - LLViewerParcelMgr::processParcelAccessListReply); - msg->setHandlerFunc("ParcelDwellReply", - LLViewerParcelMgr::processParcelDwellReply); - - msg->setHandlerFunc("AvatarPropertiesReply", - &LLAvatarPropertiesProcessor::processAvatarLegacyPropertiesReply); - msg->setHandlerFunc("AvatarInterestsReply", - &LLAvatarPropertiesProcessor::processAvatarInterestsReply); - msg->setHandlerFunc("AvatarGroupsReply", - &LLAvatarPropertiesProcessor::processAvatarGroupsReply); - msg->setHandlerFunc("AvatarNotesReply", - &LLAvatarPropertiesProcessor::processAvatarNotesReply); - msg->setHandlerFunc("AvatarPicksReply", - &LLAvatarPropertiesProcessor::processAvatarPicksReply); - msg->setHandlerFunc("AvatarClassifiedReply", - &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply); - - msg->setHandlerFuncFast(_PREHASH_CreateGroupReply, - LLGroupMgr::processCreateGroupReply); - msg->setHandlerFuncFast(_PREHASH_JoinGroupReply, - LLGroupMgr::processJoinGroupReply); - msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply, - LLGroupMgr::processEjectGroupMemberReply); - msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply, - LLGroupMgr::processLeaveGroupReply); - msg->setHandlerFuncFast(_PREHASH_GroupProfileReply, - LLGroupMgr::processGroupPropertiesReply); + msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties); + msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily); + msg->setHandlerFuncFast(_PREHASH_ForceObjectSelect, LLSelectMgr::processForceObjectSelect); - // ratings deprecated - // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, - // LLFloaterRate::processReputationIndividualReply); + msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply); + msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate); + msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv); + msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container); + msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply, LLLiveLSLEditor::processScriptRunningReply); - msg->setHandlerFunc("ScriptControlChange", - LLAgent::processScriptControlChange ); + msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack); - msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect); + msg->setHandlerFuncFast(_PREHASH_LogoutReply, process_logout_reply); - msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers); + //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility, LLAgent::processAddModifyAbility); + //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility, LLAgent::processRemoveModifyAbility); + msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate, LLAgent::processAgentDataUpdate); + msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate, LLAgent::processAgentGroupDataUpdate); + msg->setHandlerFuncFast(_PREHASH_AgentDropGroup, LLAgent::processAgentDropGroup); + // land ownership messages + msg->setHandlerFuncFast(_PREHASH_ParcelOverlay, LLViewerParcelMgr::processParcelOverlay); + msg->setHandlerFuncFast(_PREHASH_ParcelProperties, LLViewerParcelMgr::processParcelProperties); + msg->setHandlerFuncFast(_PREHASH_ParcelAccessListReply, LLViewerParcelMgr::processParcelAccessListReply); + msg->setHandlerFuncFast(_PREHASH_ParcelDwellReply, LLViewerParcelMgr::processParcelDwellReply); + + msg->setHandlerFuncFast(_PREHASH_AvatarPropertiesReply, LLAvatarPropertiesProcessor::processAvatarLegacyPropertiesReply); + msg->setHandlerFuncFast(_PREHASH_AvatarInterestsReply, LLAvatarPropertiesProcessor::processAvatarInterestsReply); + msg->setHandlerFuncFast(_PREHASH_AvatarGroupsReply, LLAvatarPropertiesProcessor::processAvatarGroupsReply); + msg->setHandlerFuncFast(_PREHASH_AvatarNotesReply, LLAvatarPropertiesProcessor::processAvatarNotesReply); + msg->setHandlerFuncFast(_PREHASH_AvatarPicksReply, LLAvatarPropertiesProcessor::processAvatarPicksReply); + msg->setHandlerFuncFast(_PREHASH_AvatarClassifiedReply, LLAvatarPropertiesProcessor::processAvatarClassifiedsReply); + + msg->setHandlerFuncFast(_PREHASH_CreateGroupReply, LLGroupMgr::processCreateGroupReply); + msg->setHandlerFuncFast(_PREHASH_JoinGroupReply, LLGroupMgr::processJoinGroupReply); + msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply, LLGroupMgr::processEjectGroupMemberReply); + msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply, LLGroupMgr::processLeaveGroupReply); + msg->setHandlerFuncFast(_PREHASH_GroupProfileReply, LLGroupMgr::processGroupPropertiesReply); + + // ratings deprecated + //msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, LLFloaterRate::processReputationIndividualReply); - msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply, - LLPanelGroupLandMoney::processGroupAccountSummaryReply); - msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply, - LLPanelGroupLandMoney::processGroupAccountDetailsReply); - msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply, - LLPanelGroupLandMoney::processGroupAccountTransactionsReply); + msg->setHandlerFuncFast(_PREHASH_ScriptControlChange, LLAgent::processScriptControlChange ); + msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect); + msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers); + msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply, LLPanelGroupLandMoney::processGroupAccountSummaryReply); + msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply, LLPanelGroupLandMoney::processGroupAccountDetailsReply); + msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply, LLPanelGroupLandMoney::processGroupAccountTransactionsReply); - msg->setHandlerFuncFast(_PREHASH_UserInfoReply, - process_user_info_reply); + msg->setHandlerFuncFast(_PREHASH_UserInfoReply, process_user_info_reply); - msg->setHandlerFunc("RegionHandshake", process_region_handshake, NULL); + msg->setHandlerFuncFast(_PREHASH_RegionHandshake, process_region_handshake); - msg->setHandlerFunc("TeleportStart", process_teleport_start ); - msg->setHandlerFunc("TeleportProgress", process_teleport_progress); - msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL); - msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL); + msg->setHandlerFuncFast(_PREHASH_TeleportStart, process_teleport_start); + msg->setHandlerFuncFast(_PREHASH_TeleportProgress, process_teleport_progress); + msg->setHandlerFuncFast(_PREHASH_TeleportFailed, process_teleport_failed); + msg->setHandlerFuncFast(_PREHASH_TeleportLocal, process_teleport_local); - msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL); + msg->setHandlerFuncFast(_PREHASH_ImageNotInDatabase, LLViewerTextureList::processImageNotInDatabase); - msg->setHandlerFuncFast(_PREHASH_GroupMembersReply, - LLGroupMgr::processGroupMembersReply); - msg->setHandlerFunc("GroupRoleDataReply", - LLGroupMgr::processGroupRoleDataReply); - msg->setHandlerFunc("GroupRoleMembersReply", - LLGroupMgr::processGroupRoleMembersReply); - msg->setHandlerFunc("GroupTitlesReply", - LLGroupMgr::processGroupTitlesReply); + msg->setHandlerFuncFast(_PREHASH_GroupMembersReply, LLGroupMgr::processGroupMembersReply); + msg->setHandlerFuncFast(_PREHASH_GroupRoleDataReply, LLGroupMgr::processGroupRoleDataReply); + msg->setHandlerFuncFast(_PREHASH_GroupRoleMembersReply, LLGroupMgr::processGroupRoleMembersReply); + msg->setHandlerFuncFast(_PREHASH_GroupTitlesReply, LLGroupMgr::processGroupTitlesReply); // Special handler as this message is sometimes used for group land. - msg->setHandlerFunc("PlacesReply", process_places_reply); - msg->setHandlerFunc("GroupNoticesListReply", LLPanelGroupNotices::processGroupNoticesListReply); + msg->setHandlerFuncFast(_PREHASH_PlacesReply, process_places_reply); + msg->setHandlerFuncFast(_PREHASH_GroupNoticesListReply, LLPanelGroupNotices::processGroupNoticesListReply); - msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply); + msg->setHandlerFuncFast(_PREHASH_AvatarPickerReply, LLFloaterAvatarPicker::processAvatarPickerReply); - msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply); - msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply); - msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply); + msg->setHandlerFuncFast(_PREHASH_MapBlockReply, LLWorldMapMessage::processMapBlockReply); + msg->setHandlerFuncFast(_PREHASH_MapItemReply, LLWorldMapMessage::processMapItemReply); + msg->setHandlerFuncFast(_PREHASH_EventInfoReply, LLEventNotifier::processEventInfoReply); - msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); - msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply); - msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply); - msg->setHandlerFunc("ScriptDialog", process_script_dialog); - msg->setHandlerFunc("LoadURL", process_load_url); - msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request); - msg->setHandlerFunc("EstateCovenantReply", process_covenant_reply); + msg->setHandlerFuncFast(_PREHASH_PickInfoReply, LLAvatarPropertiesProcessor::processPickInfoReply); + msg->setHandlerFuncFast(_PREHASH_ClassifiedInfoReply, LLAvatarPropertiesProcessor::processClassifiedInfoReply); + msg->setHandlerFuncFast(_PREHASH_ParcelInfoReply, LLRemoteParcelInfoProcessor::processParcelInfoReply); + msg->setHandlerFuncFast(_PREHASH_ScriptDialog, process_script_dialog); + msg->setHandlerFuncFast(_PREHASH_LoadURL, process_load_url); + msg->setHandlerFuncFast(_PREHASH_ScriptTeleportRequest, process_script_teleport_request); + msg->setHandlerFuncFast(_PREHASH_EstateCovenantReply, process_covenant_reply); // calling cards - msg->setHandlerFunc("OfferCallingCard", process_offer_callingcard); - msg->setHandlerFunc("AcceptCallingCard", process_accept_callingcard); - msg->setHandlerFunc("DeclineCallingCard", process_decline_callingcard); + msg->setHandlerFuncFast(_PREHASH_OfferCallingCard, process_offer_callingcard); + msg->setHandlerFuncFast(_PREHASH_AcceptCallingCard, process_accept_callingcard); + msg->setHandlerFuncFast(_PREHASH_DeclineCallingCard, process_decline_callingcard); - msg->setHandlerFunc("ParcelObjectOwnersReply", LLPanelLandObjects::processParcelObjectOwnersReply); + msg->setHandlerFuncFast(_PREHASH_ParcelObjectOwnersReply, LLPanelLandObjects::processParcelObjectOwnersReply); - msg->setHandlerFunc("InitiateDownload", process_initiate_download); - msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply); - msg->setHandlerFunc("GenericMessage", process_generic_message); - msg->setHandlerFunc("GenericStreamingMessage", process_generic_streaming_message); - msg->setHandlerFunc("LargeGenericMessage", process_large_generic_message); + msg->setHandlerFuncFast(_PREHASH_InitiateDownload, process_initiate_download); + msg->setHandlerFuncFast(_PREHASH_LandStatReply, LLFloaterTopObjects::handle_land_reply); + msg->setHandlerFuncFast(_PREHASH_GenericMessage, process_generic_message); + msg->setHandlerFuncFast(_PREHASH_GenericStreamingMessage, process_generic_streaming_message); + msg->setHandlerFuncFast(_PREHASH_LargeGenericMessage, process_large_generic_message); - msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); + msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); } void asset_callback_nothing(const LLUUID&, LLAssetType::EType, void*, S32) diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index 7ef2c8d6979..1784179237a 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -804,16 +804,16 @@ bool LLBufferedAssetUploadInfo::failedUpload(LLSD &result, std::string &reason) LLScriptAssetUpload::LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish, uploadFailed_f failed): LLBufferedAssetUploadInfo(itemId, LLAssetType::AT_LSL_TEXT, buffer, finish, failed), mExerienceId(), - mTargetType(MONO), + mCompileTarget("mono"), mIsRunning(false) { } -LLScriptAssetUpload::LLScriptAssetUpload(LLUUID taskId, LLUUID itemId, TargetType_t targetType, +LLScriptAssetUpload::LLScriptAssetUpload(LLUUID taskId, LLUUID itemId, std::string compileTarget, bool isRunning, LLUUID exerienceId, std::string buffer, taskUploadFinish_f finish, uploadFailed_f failed): LLBufferedAssetUploadInfo(taskId, itemId, LLAssetType::AT_LSL_TEXT, buffer, finish, failed), mExerienceId(exerienceId), - mTargetType(targetType), + mCompileTarget(compileTarget), mIsRunning(isRunning) { } @@ -832,7 +832,7 @@ LLSD LLScriptAssetUpload::generatePostBody() body["task_id"] = getTaskId(); body["item_id"] = getItemId(); body["is_script_running"] = getIsRunning(); - body["target"] = (getTargetType() == MONO) ? "mono" : "lsl2"; + body["target"] = getCompileTarget(); body["experience"] = getExerienceId(); } diff --git a/indra/newview/llviewerassetupload.h b/indra/newview/llviewerassetupload.h index 365436ede0a..c3c570efb2b 100644 --- a/indra/newview/llviewerassetupload.h +++ b/indra/newview/llviewerassetupload.h @@ -251,25 +251,19 @@ class LLBufferedAssetUploadInfo : public LLResourceUploadInfo class LLScriptAssetUpload : public LLBufferedAssetUploadInfo { public: - enum TargetType_t - { - LSL2, - MONO - }; - LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish, uploadFailed_f failed); - LLScriptAssetUpload(LLUUID taskId, LLUUID itemId, TargetType_t targetType, + LLScriptAssetUpload(LLUUID taskId, LLUUID itemId, std::string compileTarget, bool isRunning, LLUUID exerienceId, std::string buffer, taskUploadFinish_f finish, uploadFailed_f failed); virtual LLSD generatePostBody(); LLUUID getExerienceId() const { return mExerienceId; } - TargetType_t getTargetType() const { return mTargetType; } + const std::string& getCompileTarget() const { return mCompileTarget; } bool getIsRunning() const { return mIsRunning; } private: LLUUID mExerienceId; - TargetType_t mTargetType; + std::string mCompileTarget; bool mIsRunning; }; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 80c75ec9194..fb6b8b12f12 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7761,13 +7761,13 @@ class LLToolsSelectedScriptAction : public view_listener_t bool handleEvent(const LLSD& userdata) { std::string action = userdata.asString(); - bool mono = false; + std::string target = "lsl2"; std::string msg, name; std::string title; if (action == "compile mono") { name = "compile_queue"; - mono = true; + target = "mono"; msg = "Recompile"; title = LLTrans::getString("CompileQueueTitle"); } @@ -7800,7 +7800,7 @@ class LLToolsSelectedScriptAction : public view_listener_t LLFloaterScriptQueue* queue =LLFloaterReg::getTypedInstance(name, LLSD(id)); if (queue) { - queue->setMono(mono); + queue->setCompileTarget(target); if (queue_actions(queue, msg)) { queue->setTitle(title); diff --git a/indra/newview/skins/default/xui/en/floater_live_lsleditor.xml b/indra/newview/skins/default/xui/en/floater_live_lsleditor.xml index e30c519c8a6..4d15522c76a 100644 --- a/indra/newview/skins/default/xui/en/floater_live_lsleditor.xml +++ b/indra/newview/skins/default/xui/en/floater_live_lsleditor.xml @@ -7,7 +7,7 @@ height="607" layout="topleft" min_height="271" - min_width="328" + min_width="600" name="script ed float" help_topic="script_ed_float" save_rect="true" @@ -62,7 +62,6 @@ - + follows="bottom|left" + label="Use Experience:" + name="enable_xp"/> - Date: Mon, 11 Aug 2025 18:50:34 -0700 Subject: [PATCH 072/145] A ??) sequence was mis-interpreted by the pre-commit hooks as a trigraph sequence. --- indra/media_plugins/cef/media_plugin_cef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index d77eb83b00e..3f45ac971a8 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -617,7 +617,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string) mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this)); mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1, std::placeholders::_2)); - // CEF 139 seems to have introduced a loading failure at the login page (only??) I haven't seen it on + // CEF 139 seems to have introduced a loading failure at the login page (only?) I haven't seen it on // any other page and it only happens about 1 in 8 times. Without this handler for the error page // (red box, error message/code/url) the page load recovers after display a brief built in error. // Not ideal but better than stopping altgoether. Will restore this once I discover the error. From f03cd219a91740de9f406cfae5bbc15194156c78 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 11 Aug 2025 18:40:16 +0200 Subject: [PATCH 073/145] Fix clang compiler issues due to unused variables --- indra/llrender/llrendertarget.cpp | 16 ---------------- indra/newview/gltf/asset.cpp | 4 ++++ indra/newview/lldrawpoolwater.cpp | 2 -- indra/newview/llstartup.cpp | 2 -- indra/newview/llviewertexture.cpp | 2 -- indra/newview/llvoavatar.cpp | 8 -------- indra/newview/llvoicewebrtc.cpp | 4 ---- 7 files changed, 4 insertions(+), 34 deletions(-) diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 38bc5ff3315..0b0d69812f0 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -492,22 +492,6 @@ U32 LLRenderTarget::getNumTextures() const void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilterOptions filter_options) { gGL.getTexUnit(channel)->bindManual(mUsage, getTexture(index), filter_options == LLTexUnit::TFO_TRILINEAR || filter_options == LLTexUnit::TFO_ANISOTROPIC); - - bool isSRGB = false; - llassert(mInternalFormat.size() > index); - switch (mInternalFormat[index]) - { - case GL_SRGB: - case GL_SRGB8: - case GL_SRGB_ALPHA: - case GL_SRGB8_ALPHA8: - isSRGB = true; - break; - - default: - break; - } - gGL.getTexUnit(channel)->setTextureFilteringOption(filter_options); } diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index e24aea4a28c..28f30ae1c97 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -589,7 +589,9 @@ bool Asset::prep() for (U32 variant = 0; variant < LLGLSLShader::NUM_GLTF_VARIANTS; ++variant) { +#ifdef SHOW_ASSERT U32 attribute_mask = 0; +#endif // for each mesh for (auto& mesh : mMeshes) { @@ -607,7 +609,9 @@ bool Asset::prep() // all primitives of a given variant and material should all have the same attribute mask llassert(attribute_mask == 0 || primitive.mAttributeMask == attribute_mask); +#ifdef SHOW_ASSERT attribute_mask |= primitive.mAttributeMask; +#endif } } } diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 7d58511d41e..cdf3244389b 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -143,7 +143,6 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) gGL.setColorMask(true, true); LLColor3 light_diffuse(0, 0, 0); - F32 light_exp = 0.0f; LLEnvironment& environment = LLEnvironment::instance(); LLSettingsWater::ptr_t pwater = environment.getCurrentWater(); @@ -170,7 +169,6 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) // Apply magic numbers translating light direction into intensities light_dir.normalize(); F32 ground_proj_sq = light_dir.mV[0] * light_dir.mV[0] + light_dir.mV[1] * light_dir.mV[1]; - light_exp = llmax(32.f, 256.f * powf(ground_proj_sq, 16.0f)); if (0.f < light_diffuse.normalize()) // Normalizing a color? Puzzling... { light_diffuse *= (1.5f + (6.f * ground_proj_sq)); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 2409b71f003..ba7437798a9 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -342,13 +342,11 @@ void pump_idle_startup_network(void) { // while there are message to process: // process one then call display_startup() - S32 num_messages = 0; { LockMessageChecker lmc(gMessageSystem); while (lmc.checkAllMessages(gFrameCount, gServicePump)) { display_startup(); - ++num_messages; } lmc.processAcks(); } diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 4a9dd1c1b64..1c3674de1df 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -524,7 +524,6 @@ void LLViewerTexture::updateClass() bool is_low = is_sys_low || over_pct > 0.f; static bool was_low = false; - static bool was_sys_low = false; if (is_low && !was_low) { @@ -542,7 +541,6 @@ void LLViewerTexture::updateClass() } was_low = is_low; - was_sys_low = is_sys_low; if (is_low) { diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index dd59979a6ce..283a80a1ed7 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -4766,14 +4766,6 @@ bool LLVOAvatar::updateCharacter(LLAgent &agent) } bool visible = isVisible(); - bool is_control_avatar = isControlAvatar(); // capture state to simplify tracing - bool is_attachment = false; - - if (is_control_avatar) - { - LLControlAvatar *cav = dynamic_cast(this); - is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects - } // For fading out the names above heads, only let the timer // run if we're visible. diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 627d759df41..72baa393cf5 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -2264,7 +2264,6 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro(connectionPtr_t connection) return; } - bool iceCompleted = false; LLSD body; if (!connection->mIceCandidates.empty() || connection->mIceCompleted) { @@ -2303,7 +2302,6 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro(connectionPtr_t connection) LLSD body_candidate; body_candidate["completed"] = true; body["candidate"] = body_candidate; - iceCompleted = connection->mIceCompleted; connection->mIceCompleted = false; } @@ -2926,7 +2924,6 @@ void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool b return; } boost::json::object voice_data = voice_data_parsed.as_object(); - bool new_participant = false; boost::json::object mute; boost::json::object user_gain; for (auto &participant_elem : voice_data) @@ -2979,7 +2976,6 @@ void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool b } } - new_participant |= joined; if (!participant && joined && (primary || !isSpatial())) { participant = LLWebRTCVoiceClient::getInstance()->addParticipantByID(mChannelID, agent_id, mRegionID); From e3d15a9146d375368066cdbcf2a45f40165175f1 Mon Sep 17 00:00:00 2001 From: Signal Linden Date: Tue, 12 Aug 2025 09:02:07 -0700 Subject: [PATCH 074/145] Chore: Move message.xml to scripts/messages (#4501) * Move message.xml to scripts/messages Get rid of the top-level etc/ directory by moving its only contents: message.xml to scripts/messages * Move message.xml to app_settings * Remove unneeded inclusion in viewer_manifest.py --- indra/newview/CMakeLists.txt | 4 ++-- {etc => indra/newview/app_settings}/message.xml | 0 indra/newview/viewer_manifest.py | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) rename {etc => indra/newview/app_settings}/message.xml (100%) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 759a40fc086..8ed7876da19 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1664,7 +1664,7 @@ set(viewer_APPSETTINGS_FILES app_settings/toolbars.xml app_settings/trees.xml app_settings/viewerart.xml - ${CMAKE_SOURCE_DIR}/../etc/message.xml + app_settings/message.xml ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg packages-info.txt featuretable.txt @@ -1758,7 +1758,7 @@ if (WINDOWS) set(COPY_INPUT_DEPENDENCIES # The following commented dependencies are determined at variably at build time. Can't do this here. - ${CMAKE_SOURCE_DIR}/../etc/message.xml + app_settings/message.xml ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg ${SHARED_LIB_STAGING_DIR}/openjp2.dll ${SHARED_LIB_STAGING_DIR}/llwebrtc.dll diff --git a/etc/message.xml b/indra/newview/app_settings/message.xml similarity index 100% rename from etc/message.xml rename to indra/newview/app_settings/message.xml diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 04c3fea93aa..cf5e7485132 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -63,7 +63,6 @@ def is_packaging_viewer(self): def construct(self): super(ViewerManifest, self).construct() self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg") - self.path(src="../../etc/message.xml", dst="app_settings/message.xml") if self.is_packaging_viewer(): with self.prefix(src_dst="app_settings"): From 9c6fd95bdb2bfd99a01c2f2a0dadcf14d3febac0 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 12 Aug 2025 20:35:48 +0300 Subject: [PATCH 075/145] Revert "Fix: ignore *pass-on* counters when detecting left-button grabs (#3990)" This reverts commit 65d70a8d8f211b462481e93f919a100c8b3b2af5. --- indra/newview/llagent.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 039bd4da2ad..2161dbe19e4 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3469,14 +3469,11 @@ void LLAgent::initOriginGlobal(const LLVector3d &origin_global) bool LLAgent::leftButtonGrabbed() const { - if (gAgentCamera.cameraMouselook()) - { - return mControlsTakenCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0; - } - else - { - return mControlsTakenCount[CONTROL_LBUTTON_DOWN_INDEX] > 0; - } + const bool camera_mouse_look = gAgentCamera.cameraMouselook(); + return (!camera_mouse_look && mControlsTakenCount[CONTROL_LBUTTON_DOWN_INDEX] > 0) + || (camera_mouse_look && mControlsTakenCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0) + || (!camera_mouse_look && mControlsTakenPassedOnCount[CONTROL_LBUTTON_DOWN_INDEX] > 0) + || (camera_mouse_look && mControlsTakenPassedOnCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0); } bool LLAgent::rotateGrabbed() const From 8145d99f80d55c4da88adb6909386bd5c25fd743 Mon Sep 17 00:00:00 2001 From: fmartian Date: Wed, 13 Aug 2025 15:25:37 +0200 Subject: [PATCH 076/145] #4519 Check for "://" as schema separator in a SLURL Check for "://" as schema separator when testing if the passed in address contains a schema. A ':' alone could also indicate a port separator as part of the hostname and throw off the parsing. (#4543) --- indra/newview/llslurl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index 9e567e32624..6238a1145cf 100644 --- a/indra/newview/llslurl.cpp +++ b/indra/newview/llslurl.cpp @@ -71,10 +71,10 @@ LLSLURL::LLSLURL(const std::string& slurl) { LLURI slurl_uri; // parse the slurl as a uri - if (slurl.find(':') == std::string::npos) + if (slurl.find("://") == std::string::npos) { - // There may be no scheme ('secondlife:' etc.) passed in. In that case - // we want to normalize the slurl by putting the appropriate scheme + // There may be no scheme ('secondlife://', 'https://' etc.) passed in. In that + // case we want to normalize the slurl by putting the appropriate scheme // in front of the slurl. So, we grab the appropriate slurl base // from the grid manager which may be http://slurl.com/secondlife/ for maingrid, or // https:///region/ for Standalone grid (the word region, not the region name) From 4c65a43e1700f0a669006b08b1f4f10293f2e947 Mon Sep 17 00:00:00 2001 From: Brad Linden <46733234+brad-linden@users.noreply.github.com> Date: Thu, 14 Aug 2025 09:47:22 -0700 Subject: [PATCH 077/145] CMake 4.10 compatibility fixes (#4548) --- autobuild.xml | 18 +++++++++--------- indra/newview/CMakeLists.txt | 25 ++++++++++--------------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index f792bac7895..1d75fe5043f 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1435,11 +1435,11 @@ creds github hash - 9e59c93c7110e87b4ff3db330f11a23c50e5000f + 7facda95e2f00c260513f3d4db42588fa8ba703c hash_algorithm sha1 url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/178910560 + https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/196289774 name darwin64 @@ -1451,11 +1451,11 @@ creds github hash - 7ed994db5bafa9a7ad09a1b53da850a84715c65e + 01d08f13c7bc8d1b95b0330fa6833b7d8274e4d0 hash_algorithm sha1 url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/178910561 + https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/196289775 name linux64 @@ -1467,24 +1467,24 @@ creds github hash - 66824c02e0e5eabbfbe37bfb173360195f89697c + 6d00345c7d3471bc5f7c1218e014dd0f1a2c069b hash_algorithm sha1 url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/178910562 + https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/196289778 name windows64 + copyright + Copyright (c) 2010, Linden Research, Inc. license internal license_file LICENSES/llphysicsextensions.txt - copyright - Copyright (c) 2010, Linden Research, Inc. version - 1.0.66e6919 + 1.0.11137145495 name llphysicsextensions_source diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 1315baf7400..62af812971d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1420,7 +1420,7 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt" "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}\n") set_source_files_properties( - llversioninfo.cpp tests/llversioninfo_test.cpp + llversioninfo.cpp tests/llversioninfo_test.cpp PROPERTIES COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" # see BuildVersion.cmake ) @@ -1635,7 +1635,7 @@ endif (WINDOWS) file(GLOB_RECURSE viewer_XUI_FILES LIST_DIRECTORIES FALSE ${CMAKE_CURRENT_SOURCE_DIR}/skins/*.xml) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/skins PREFIX "XUI Files" FILES ${viewer_XUI_FILES}) -set_source_files_properties(${viewer_XUI_FILES} +set_source_files_properties(${viewer_XUI_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) list(APPEND viewer_SOURCE_FILES ${viewer_XUI_FILES}) @@ -1643,7 +1643,7 @@ list(APPEND viewer_SOURCE_FILES ${viewer_XUI_FILES}) file(GLOB_RECURSE viewer_SHADER_FILES LIST_DIRECTORIES FALSE ${CMAKE_CURRENT_SOURCE_DIR}/app_settings/shaders/*.glsl) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/app_settings/shaders PREFIX "Shaders" FILES ${viewer_SHADER_FILES}) -set_source_files_properties(${viewer_SHADER_FILES} +set_source_files_properties(${viewer_SHADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) list(APPEND viewer_SOURCE_FILES ${viewer_SHADER_FILES}) @@ -1970,7 +1970,7 @@ endif (WINDOWS) # one of these being libz where you can find four or more versions in play # at once. On Linux, libz can be found at link and run time via a number # of paths: -# +# # => -lfreetype # => libz.so.1 (on install machine, not build) # => -lSDL @@ -2046,7 +2046,7 @@ foreach(elem ${country_codes}) set(emoji_mapping_src_file "${emoji_mapping_src_folder}/${elem}/emoji_characters.xml") set(emoji_mapping_dst_file - "${emoji_mapping_dst_folder}/${elem}/emoji_characters.xml") + "${emoji_mapping_dst_folder}/${elem}/emoji_characters.xml") configure_file(${emoji_mapping_src_file} ${emoji_mapping_dst_file} COPYONLY) endforeach() @@ -2148,7 +2148,7 @@ if (DARWIN) # https://blog.kitware.com/upcoming-in-cmake-2-8-12-osx-rpath-support/ set(CMAKE_MACOSX_RPATH 1) - + set_target_properties( ${VIEWER_BINARY_NAME} PROPERTIES @@ -2191,9 +2191,6 @@ if (DARWIN) --grid=${GRID} --source=${CMAKE_CURRENT_SOURCE_DIR} --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - DEPENDS - ${VIEWER_BINARY_NAME} - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef) @@ -2228,8 +2225,6 @@ if (DARWIN) --touch=${CMAKE_CURRENT_BINARY_DIR}/$,$,>/.${product}.bat --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt ${SIGNING_SETTING} - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) endif (PACKAGE) endif (DARWIN) @@ -2269,7 +2264,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE PROPERTIES XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" XCODE_ATTRIBUTE_DWARF_DSYM_FOLDER_PATH "${SYMBOLS_STAGING_DIR}/dSYMs") - + add_custom_command(OUTPUT "${VIEWER_APP_XCARCHIVE}" COMMAND "zip" ARGS @@ -2304,7 +2299,7 @@ if (LL_TESTS) # llremoteparcelrequest.cpp llviewerhelputil.cpp llversioninfo.cpp -# llvocache.cpp +# llvocache.cpp llworldmap.cpp llworldmipmap.cpp ) @@ -2313,7 +2308,7 @@ if (LL_TESTS) llworldmap.cpp llworldmipmap.cpp PROPERTIES - LL_TEST_ADDITIONAL_SOURCE_FILES + LL_TEST_ADDITIONAL_SOURCE_FILES tests/llviewertexture_stub.cpp #llviewertexturelist.cpp ) @@ -2347,7 +2342,7 @@ if (LL_TESTS) llworldmap.cpp llworldmipmap.cpp PROPERTIES - LL_TEST_ADDITIONAL_SOURCE_FILES + LL_TEST_ADDITIONAL_SOURCE_FILES tests/llviewertexture_stub.cpp ) From 68d3d5cd739693dd0bf42c93c02673e2dd74accc Mon Sep 17 00:00:00 2001 From: Signal Linden Date: Fri, 15 Aug 2025 19:57:55 -0700 Subject: [PATCH 078/145] Remove unused vstool, files (#4500) Clean up of some unused files: - vstool - No longer used - indra/edit-me-to-trigger-new-build.txt - Shouldn't be needed... - win_crash_logger/* - Empty directory --- .gitattributes | 3 - indra/edit-me-to-trigger-new-build.txt | 1 - indra/tools/vstool/DispatchUtility.cs | 271 --------- indra/tools/vstool/README.txt | 9 - indra/tools/vstool/VSTool.csproj | 98 ---- indra/tools/vstool/VSTool.exe | Bin 24576 -> 0 bytes indra/tools/vstool/VSTool.sln | 19 - indra/tools/vstool/app.config | 3 - indra/tools/vstool/main.cs | 733 ------------------------- indra/win_crash_logger/README.txt | 3 - 10 files changed, 1140 deletions(-) delete mode 100644 indra/edit-me-to-trigger-new-build.txt delete mode 100644 indra/tools/vstool/DispatchUtility.cs delete mode 100644 indra/tools/vstool/README.txt delete mode 100755 indra/tools/vstool/VSTool.csproj delete mode 100755 indra/tools/vstool/VSTool.exe delete mode 100755 indra/tools/vstool/VSTool.sln delete mode 100644 indra/tools/vstool/app.config delete mode 100755 indra/tools/vstool/main.cs delete mode 100644 indra/win_crash_logger/README.txt diff --git a/.gitattributes b/.gitattributes index 30cc9de8f17..5c7f5b73b07 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,8 +1,5 @@ * text eol=lf -# VSTool (normalization disabled) -indra/tools/vstool/* -text - # Images *.bmp binary *.BMP binary diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt deleted file mode 100644 index 8b137891791..00000000000 --- a/indra/edit-me-to-trigger-new-build.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/indra/tools/vstool/DispatchUtility.cs b/indra/tools/vstool/DispatchUtility.cs deleted file mode 100644 index 6056ac55a13..00000000000 --- a/indra/tools/vstool/DispatchUtility.cs +++ /dev/null @@ -1,271 +0,0 @@ -#region Using Directives - -using System; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; -using System.Reflection; -using System.Security.Permissions; - -#endregion - -namespace TestDispatchUtility -{ - /// - /// Provides helper methods for working with COM IDispatch objects that have a registered type library. - /// - public static class DispatchUtility - { - #region Private Constants - - private const int S_OK = 0; //From WinError.h - private const int LOCALE_SYSTEM_DEFAULT = 2 << 10; //From WinNT.h == 2048 == 0x800 - - #endregion - - #region Public Methods - - /// - /// Gets whether the specified object implements IDispatch. - /// - /// An object to check. - /// True if the object implements IDispatch. False otherwise. - public static bool ImplementsIDispatch(object obj) - { - bool result = obj is IDispatchInfo; - return result; - } - - /// - /// Gets a Type that can be used with reflection. - /// - /// An object that implements IDispatch. - /// Whether an exception should be thrown if a Type can't be obtained. - /// A .NET Type that can be used with reflection. - /// If doesn't implement IDispatch. - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - public static Type GetType(object obj, bool throwIfNotFound) - { - RequireReference(obj, "obj"); - Type result = GetType((IDispatchInfo)obj, throwIfNotFound); - return result; - } - - /// - /// Tries to get the DISPID for the requested member name. - /// - /// An object that implements IDispatch. - /// The name of a member to lookup. - /// If the method returns true, this holds the DISPID on output. - /// If the method returns false, this value should be ignored. - /// True if the member was found and resolved to a DISPID. False otherwise. - /// If doesn't implement IDispatch. - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - public static bool TryGetDispId(object obj, string name, out int dispId) - { - RequireReference(obj, "obj"); - bool result = TryGetDispId((IDispatchInfo)obj, name, out dispId); - return result; - } - - /// - /// Invokes a member by DISPID. - /// - /// An object that implements IDispatch. - /// The DISPID of a member. This can be obtained using - /// . - /// The arguments to pass to the member. - /// The member's return value. - /// - /// This can invoke a method or a property get accessor. - /// - public static object Invoke(object obj, int dispId, object[] args) - { - string memberName = "[DispId=" + dispId + "]"; - object result = Invoke(obj, memberName, args); - return result; - } - - /// - /// Invokes a member by name. - /// - /// An object. - /// The name of the member to invoke. - /// The arguments to pass to the member. - /// The member's return value. - /// - /// This can invoke a method or a property get accessor. - /// - public static object Invoke(object obj, string memberName, object[] args) - { - RequireReference(obj, "obj"); - Type type = obj.GetType(); - object result = type.InvokeMember(memberName, BindingFlags.InvokeMethod | BindingFlags.GetProperty, - null, obj, args, null); - return result; - } - - #endregion - - #region Private Methods - - /// - /// Requires that the value is non-null. - /// - /// The type of the value. - /// The value to check. - /// The name of the value. - private static void RequireReference(T value, string name) where T : class - { - if (value == null) - { - throw new ArgumentNullException(name); - } - } - - /// - /// Gets a Type that can be used with reflection. - /// - /// An object that implements IDispatch. - /// Whether an exception should be thrown if a Type can't be obtained. - /// A .NET Type that can be used with reflection. - private static Type GetType(IDispatchInfo dispatch, bool throwIfNotFound) - { - RequireReference(dispatch, "dispatch"); - - Type result = null; - int typeInfoCount; - int hr = dispatch.GetTypeInfoCount(out typeInfoCount); - if (hr == S_OK && typeInfoCount > 0) - { - // Type info isn't usually culture-aware for IDispatch, so we might as well pass - // the default locale instead of looking up the current thread's LCID each time - // (via CultureInfo.CurrentCulture.LCID). - dispatch.GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, out result); - } - - if (result == null && throwIfNotFound) - { - // If the GetTypeInfoCount called failed, throw an exception for that. - Marshal.ThrowExceptionForHR(hr); - - // Otherwise, throw the same exception that Type.GetType would throw. - throw new TypeLoadException(); - } - - return result; - } - - /// - /// Tries to get the DISPID for the requested member name. - /// - /// An object that implements IDispatch. - /// The name of a member to lookup. - /// If the method returns true, this holds the DISPID on output. - /// If the method returns false, this value should be ignored. - /// True if the member was found and resolved to a DISPID. False otherwise. - private static bool TryGetDispId(IDispatchInfo dispatch, string name, out int dispId) - { - RequireReference(dispatch, "dispatch"); - RequireReference(name, "name"); - - bool result = false; - - // Members names aren't usually culture-aware for IDispatch, so we might as well - // pass the default locale instead of looking up the current thread's LCID each time - // (via CultureInfo.CurrentCulture.LCID). - Guid iidNull = Guid.Empty; - int hr = dispatch.GetDispId(ref iidNull, ref name, 1, LOCALE_SYSTEM_DEFAULT, out dispId); - - const int DISP_E_UNKNOWNNAME = unchecked((int)0x80020006); //From WinError.h - const int DISPID_UNKNOWN = -1; //From OAIdl.idl - if (hr == S_OK) - { - result = true; - } - else if (hr == DISP_E_UNKNOWNNAME && dispId == DISPID_UNKNOWN) - { - // This is the only supported "error" case because it means IDispatch - // is saying it doesn't know the member we asked about. - result = false; - } - else - { - // The other documented result codes are all errors. - Marshal.ThrowExceptionForHR(hr); - } - - return result; - } - - #endregion - - #region Private Interfaces - - /// - /// A partial declaration of IDispatch used to lookup Type information and DISPIDs. - /// - /// - /// This interface only declares the first three methods of IDispatch. It omits the - /// fourth method (Invoke) because there are already plenty of ways to do dynamic - /// invocation in .NET. But the first three methods provide dynamic type metadata - /// discovery, which .NET doesn't provide normally if you have a System.__ComObject - /// RCW instead of a strongly-typed RCW. - /// - /// Note: The original declaration of IDispatch is in OAIdl.idl. - /// - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [Guid("00020400-0000-0000-C000-000000000046")] - private interface IDispatchInfo - { - /// - /// Gets the number of Types that the object provides (0 or 1). - /// - /// Returns 0 or 1 for the number of Types provided by . - /// - /// http://msdn.microsoft.com/en-us/library/da876d53-cb8a-465c-a43e-c0eb272e2a12(VS.85) - /// - [PreserveSig] - int GetTypeInfoCount(out int typeInfoCount); - - /// - /// Gets the Type information for an object if returned 1. - /// - /// Must be 0. - /// Typically, LOCALE_SYSTEM_DEFAULT (2048). - /// Returns the object's Type information. - /// - /// http://msdn.microsoft.com/en-us/library/cc1ec9aa-6c40-4e70-819c-a7c6dd6b8c99(VS.85) - /// - void GetTypeInfo(int typeInfoIndex, int lcid, [MarshalAs(UnmanagedType.CustomMarshaler, - MarshalTypeRef = typeof(System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler))] out Type typeInfo); - - /// - /// Gets the DISPID of the specified member name. - /// - /// Must be IID_NULL. Pass a copy of Guid.Empty. - /// The name of the member to look up. - /// Must be 1. - /// Typically, LOCALE_SYSTEM_DEFAULT (2048). - /// If a member with the requested - /// is found, this returns its DISPID and the method's return value is 0. - /// If the method returns a non-zero value, then this parameter's output value is - /// undefined. - /// Zero for success. Non-zero for failure. - /// - /// http://msdn.microsoft.com/en-us/library/6f6cf233-3481-436e-8d6a-51f93bf91619(VS.85) - /// - [PreserveSig] - int GetDispId(ref Guid riid, ref string name, int nameCount, int lcid, out int dispId); - - // NOTE: The real IDispatch also has an Invoke method next, but we don't need it. - // We can invoke methods using .NET's Type.InvokeMember method with the special - // [DISPID=n] syntax for member "names", or we can get a .NET Type using GetTypeInfo - // and invoke methods on that through reflection. - // Type.InvokeMember: http://msdn.microsoft.com/en-us/library/de3dhzwy.aspx - } - - #endregion - } -} diff --git a/indra/tools/vstool/README.txt b/indra/tools/vstool/README.txt deleted file mode 100644 index e4191800312..00000000000 --- a/indra/tools/vstool/README.txt +++ /dev/null @@ -1,9 +0,0 @@ -VSTool is a command line utility to manipulate VisualStudio settings. - -The windows cmake project configuration uses VSTool.exe - -A handy upgrade: - figure out how to make cmake build this csharp app - - or write the app using script (jscript?!?) so it doesn't need to be built. - - diff --git a/indra/tools/vstool/VSTool.csproj b/indra/tools/vstool/VSTool.csproj deleted file mode 100755 index 7f431e85c73..00000000000 --- a/indra/tools/vstool/VSTool.csproj +++ /dev/null @@ -1,98 +0,0 @@ - - - - Local - 8.0.50727 - 2.0 - {96943E2D-1373-4617-A117-D0F997A94919} - Debug - AnyCPU - - - - - VSTool - - - JScript - Grid - IE50 - false - Exe - VSTool - Always - VSTool.VSToolMain - - - - - v2.0 - 2.0 - - - .\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - - - false - false - false - false - 4 - full - prompt - - - .\ - false - 285212672 - false - - - TRACE - - - false - 4096 - false - - - true - false - false - false - 4 - none - prompt - - - - System - - - System.Data - - - - - Code - - - - - - - - - - \ No newline at end of file diff --git a/indra/tools/vstool/VSTool.exe b/indra/tools/vstool/VSTool.exe deleted file mode 100755 index 751540413a0af3256f6bbb30f9a49c7232699d9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 zcmeHOYj7Labw0ZQb^(xt36LVCh_Y7H!w?@3MM^gHpd^ZvWICcKiyGnKUT&P`Up*6F=&ST{oFzGEUn}+`Jr(-8z$J9jETZaVCxW zoqKlykfLN|`Y#12+`Z@AbI(2JyXT&JcNZFd-Mh(0M1FiPUL<-5SN`mg<&}$hG)GoH z5}_}Jo?7#ecJQe+W7Fw^l^4#GNM@~6GM96T)`V?|nVgl*S%V{^R@Rxc6Lodrb*}2e z`-l!|KC1h6?+I_TXQ`EHv@Rn2BTI2#^IErlyQHI%U$5+D4%;t3A43T~e|)s(t&)&5 z3YYI*q|DcEA{yb^?L^-xDUnU8m?x^OAg{V=5d|xRgP?D$pc6&=OcAuz&IP_*_*NRG z*taJ{L8MTZw%zW^?7_9-vj@|a5O&6aptN-!jjZc1z7?N6M0+d9YPE_$6@e-ORRpRC zR1v5mP(`4MKox;10#yY5A0hC2-2d{2?@e_I&}TYuJ9;gV20BV)aN8gAY3S1Btta|N z3nmmahGP_m8e>BnxAFZcw>5?vOZ;$C+lIjM9^dLz+p@Os^0sUBc!((6wzA8Rx5YZ- zbtep#&tm0`dZSYVDtw_?Kv&)uht}|Vrw(O2g5s>vrn&dh&CS#dWg6?+fwA$dBij6q z066QL{P%}Fwbxs$){tszptf&GwPqW6dRtq|db^;v(#GpyRHN=M**LePvZZYF(OUGy zV~A)|xT!{u#~3&9Ao`!f0DkFbyaCMGbHLW$VV=V?27jm79Pa%zjEJMNaSq-6&NYCc zu6;+y0S@6$q0k!qF@GFW8ZNdl6#xbGE@enX(LmIQuYisYy}2gjV4!g4V;34jGw7x@ zm{GF>U#Ai5XU<_t{T(&(5?_ffHRk{-bNCW}4Rg$n#$abuY8F3)4~=omkg?&yV0osR z!xyfX0v$>&z6{DYG|sbI%EhR>czpIc4k(Og49rEGao6r_+@2}n&x@LlfU;P++z4EbY1KAtaYz-a#n&NXF1fi-zlt0Vao+mbc4Ha zU`DxpugEMES4fNbOT@XMy+QngD~_oQD}C^z#?;@L-W|Gl@uKvzvqr=M-f$PP4SsP8 z$f#e<4fm8wNt^_ir!%ZK1ezL*_G>vv?rSi`n^@fBa0$!ysL^~&gAp~Nfp@06e<0rG z^%M7SjhCgN-d;QfKK(K{t&N1$t zHD(+WZ_IO4$S~RdF?16xhC85m*sGaw%%@Q+UIrs5mr*c|sW9R&BOG6aLMjp0nUptW zyVNIc106@MF=Rw~iNn0VPDOPV%^^3cHl zzn5cr=*$DOLFFzV9fxCZGuq56!H~;4+}?*8a&;IhtjNIpan=DC{CL)o5aiUs0GgT{ua zzv;ecpfP4RNFU)KlQGlTi24SOUQ^l%zIct9KOc!KRt=-x!*n*o zG|r|9XB`>!$*;1DM7&>Li^xIzW53qp2sI>i>z^O$&uz6#>#e`KZED9~Le8|lmft;{ zm{d)PQ@uZs%;urwOIw$lR_}`=Kie^1VkOeOk4WNM^#@)_tTL@+?7;8#{0&&TbVy-1 z(ffYMVb>Jrmfkl@4m+thhuVv}^i`1u+HGCBtjIm>$8_HTjUnc56r=LGM*O+Ft`HB%YgBv}SG@v86&rr)16DYRVDA<+VeeR? zi+ZUm{Xyq>pz z6iP$^BI*<*KFHFXZP9aK7Vx-FdHTc;y&CWBW!oBp%?+XUot|k?&$cjxq;X+soOs3S zE|%3$UY<^{yh7LpLeWq(_$l^i^TX}+;M9c_xvLiY4>tYgiez~MIxFLmlQ<5&y#c2M zY6hn3@J0IO^)B}YoFxctjPtwDS6BHOnaY1ztlQ6e-gwSj325HNE=inQRLcJ`MwGKD zv|7wlK&-($C!jgJ(Dk!$-N3dx3;|{Hg(mU0o^%-yiGn(3>h#2u)a3bn zC;WzD_WR|Mj>T5>*SY2(C2}HP-=yDPtL81JrVS%`N3lv{aq7JbEy}V*)<6$(C!e;C z-J;ID|JFQ@S@Ac{^Ul8= zau<$c?TxzWbOSUaX}wn??R8;wVsU!F>;4a;ZSUw!d%hhj2ZN&2sH%QKWNI1(pZ`xMvVFYmbi7^Eg7VJ8KUd9U8>-zd?7vkF|R< z&IAkN15!KQtTXmRztegMnVm;(#TV*%UnJy1O5n?U*vaw9e(^m9_m@|0Q&xXNS672l z`Xd2@?v-V){uhC3=;y%8pjm_b2DRxQLhE^r%Y(8$;%EMwailfqW$G~udV*d->vs(< zf3GorEWrGr$>lEqyFr7p*Ta66`GPFZ`^PZKHFDf<%3f=XZb*LC&t*h%wo5(jKGrbj zV;he8xYr#4=G-OAk4Qc626HV>CDKQpoqGDM|ChdHsA=>uK>Q3S_Mg$Jr(sfU*iS&! zx{^Q)s(3z@0l{l=*ZDndzZRwa+T*AnHn{##V+iHD4CcJ3bNOG|FgU0D!`fjBUFic< zA2_UOlyRv?h^eN)LmzA;d5cd5I4uh#-}-lbmFU$3!!MDyUi;7@5a^gh}4w&g|m z&sm7uz83f@w3Mm)pe0&rs|VFce{C`21Jr9~v}XFLOAVSrTS0r)sJ1zp(^?jcfO8o> z^Yj7hX}U`*Q_mWAYisBp+3!5X{O7f`^gIV3MmVS4tF5E=ty9#k{ts*G>67af^%nX# zsO1|J^@G5twGH$omwK8$r(H)KI1{m!X8(KWI%fiz$s-zd8k0K9bsv2N%T>cJ#I4)W>Z1fK z1P8QE->9fhNncc}DiK(a{Ed`plJz!e=Sx!C8Lw<%@ExTMd2|5~5;2Lo{=o ztw0&3%_!@sALTN-S@Q3cNI^DQGuchk=`gMLO6hE31Wa`QBuht7KR%Fr9Zxy^Vp^!x^Teocpb z@4+ZL=w5n--b){*IbuD}(Z6U9K%Q-$llq?{+xIB=-R9#c*Fop4^s?`bl%&Tt57M`d|D?~#(L>rPZ3p^(NB;xs@%gmp$n@`^koG*ReUA1U zTfljpZyRE%hW-&{1APxU`*$BADheD`-PKrImgn;fstVvohuaWY+`7HvW1i*GU*A*=O9#4*v0*6 zbR2MUplvEKXEGUXIF!svt*jxFoRef$8b6-nCQn{b_<>QrRAZ|Yal}qe9!%$KIxf;h zTh{VPQLx8TPBxp&O^#={alpx9N^Eg5nX(yPnmm2j&P~EYmtrW~>JeM|%u?=TaCa!R zDLs{Q1XL#rP?>R1D(|7M=vqLdWBp^(0DH2(h=a()3>vsQ{1pf6oGma56-@_b(iPO8 zJux#i#R!%=FR;7JRyt)I9kDaXGqP4Fw;xX8*I4~RB^U1 z7#vGxW^BsYr^jby?bzs;<75){8Ji9!3&o+_qDLzLO&%%C$%;98lTE^-@J2!>u zXfY{@h2v>dPhz!-%Fs6PwnW4*Ca>Oo*IW@!fBv1O~MQ=p(WUyiY7ve<9!m*z2 z#3Xtlp52-nii4F3KyV0))LpAICem3~|8O#$V@F2ag>lRl1*{L6b+7K~K4PEDAhfxq zKcCN}Q*v7Ook`hw$%KZ%v3>oyNl#B{kx(XIij<+;Ne3y2SMso(ov;O?Y$vn4RzQs5 zM`&(!ZyGZyXlU5UrB88%r^X}7IYPkSNi~;r$?Rgrj@VOaWGAs;);WyaK3+Qq4ze1r zuj7t51y~2uf=;XI_$2Dm0A3`HV7S;EmqMbEz$C?71y_clluo3$Pa-8RfZ}iwZmXO* zm`-Bh7K-Uq!DG2gAt5ny@}o$f>6Cp*v$t|f?XamLs}@MDSU7@Ie`)tc+7nR6Nv1%I zJ38&pByppX6ewI%2OOki>1RR4`oJ_Inr4vC>Ppuc{*bw3qheu(F~Sb1IBV` z%;a6D30r_D&g93DLK%8;uM8*@A!^l7GeTf%LTVgKr%nwxNER$vq+w^)KEyv<9AdKv zif7!-#G|GV_OG?)$jRF|FD?rsxy&50V|mK3?jSL~@6MSd=N+yO$|mb z+!RhS8T@(UW~Huaj6Jz<#P)sQq$?~eKqf;olH5_zj6pFnFIK-qLB3`)z|ByGe2h{v9hhOl;< zPSZHef>!#kRPxwEn2H=MXU!JM8Bn5^}TPAiO28Y;_TJhR(q) zwzBB7)OpI)#BCe`JKagY1A0^F#VG8QJ%y~ZMWbjd;<`|S#WCPn!w4mT0OORG z_AIn|X^WP!X0fJ)dalkQZP`-ss`c%MH$4BmEI6>0uS_i^&ohySM=Cb76_<-c)v|Cl zRXk`>?o)}Vw(ZI`RLU+Izd_kpiLIKuE1mX@xl#4%h*}thSMlOCpTND&h{V1?YtT+B2S6=7BKgpc z8`UtLc^$*b8iOQfsmohwAp)?q!Am5z+YU;3ZxxrL%ce8Zx^glmb1DS(rgn`vSwccu93go;S^2PFIP~q6rL>!h}o# zwsJ84vBqhAY}*kSn}jvq7zx;tfqlx(3|cu6RwhW-wN2dnD5Slf3#E8jt6jvE?^$ZJ z#eQ?Iirq0fDkrkMH&JLr?xi`RftxXjypNTqXA;sXSS@L>wYFR--CjM!Y5fMN zLDlfiOY(Y4JiJ}Ri!N?uedYRAu6G{A9G$|~!4|@^Ri3v?=fTs`%{|w@ntut{MH{b1 zDgn!`Mp9vPHIfQLYJc_7J&dnTR^fhivRmaGQO|%}%xcX}%lafDh1UZonZ>Juqe|O) zxm2=v16!~%qKD-=_BMCC9Kg9tt?MG9Vh9m#BRVNmiqiF!X?vmWisTpLO%m*n#%SU1OnTmHAR_L+qJ4)Gf}g*pP-;|CNw0_pS74G2&~W=}I_X={Tuo zq&ySUxft6kMqRWYcyXl7%4kH+KK^PxmB->EH6J%TFE4K=u)^od5AJ&Z#D|_3`K?tKS^$-3l*x#!uJW5&tk!30Eq;q)Cu*!fOC*|%*)6MD0;Fq^7IcdE ziN#HQRZB~q84T)rtS{OhiNyACpFT*iln$w2ORX7<1kp6K3KwY5BN#{5T3A~o5(%0C zTvoNPFj`29o#3)1cEU9MvA&iT{Nl)m{(2B(XRI#*vot-T8p*}VovV2->YwYIwh-v9TTw8*cFBpW-a;S{Njz%I-5#%Bg^qYDlbd6b~x3mP| zOhjJ7rs>ixhUwGcImALibnr1`!QhwAzW&&XEzjPq8@kVkb?Qb79#d%MkEuxNOvDU6=f9zP^*M zsu=KUvZ-s!^>_>Gy%MGuZ<76G5q>Q$R++A>dB1m6yzv1?>^o!2M{@F6x^2s6dfa+( zJ#?rSe3c5S^(q2Y1gZ%9Ng|+ryKmuE8b6NZ|2{sy&`p(Ydzav|+#+Fcl>GE1O`PTN zf7+4r-+epLpvwJ{H>hvHmCyX+DEHxxc@z&6M{trG$Mq0SQzKIDG5@dr!1@<|cDoGh zN0+n?O5QPfdfe}xhKJ;d+mXH25%=Pg7C%_vJM;1hTngZKG@rzf8f+>;N}YNy)if_< z_%2fYZNa%6_k#G{la9WgJfG(aI9;)x@S?+!INAc1iss zE}uPT{hlvO$vgVXj_V>=`_wD@^aCY+beIK-8Cb@5gjeqO`~=~5 z0n$BL{OZxK?A(1Oo3Y$iY<;bp6J4#Aol80V>ZPys=-B?w-d2m>k548uPR{OYowEzA zyLZ)v>%u#eg#uokW#%lX$QAlpXGCs$AvJAhlZDP~IwhQfbF$c(aPOr_-O{)6_c zov|`p_O&Jp>J_ADwPw=&DZE_+j3<+sg6%pbm26tV8qf4i3vA!HsRRN9c5d=!Xjgg8 ztFQ-mT0T8st8mOs3K5Bpo%~hfhq!3 W1gZ#B5vU?iMWBj66@fnq1pXH?h%2K2 diff --git a/indra/tools/vstool/VSTool.sln b/indra/tools/vstool/VSTool.sln deleted file mode 100755 index 21e3d759719..00000000000 --- a/indra/tools/vstool/VSTool.sln +++ /dev/null @@ -1,19 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSTool", "VSTool.csproj", "{96943E2D-1373-4617-A117-D0F997A94919}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {96943E2D-1373-4617-A117-D0F997A94919}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {96943E2D-1373-4617-A117-D0F997A94919}.Debug|Any CPU.Build.0 = Debug|Any CPU - {96943E2D-1373-4617-A117-D0F997A94919}.Release|Any CPU.ActiveCfg = Release|Any CPU - {96943E2D-1373-4617-A117-D0F997A94919}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/indra/tools/vstool/app.config b/indra/tools/vstool/app.config deleted file mode 100644 index 8494f728ff7..00000000000 --- a/indra/tools/vstool/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/indra/tools/vstool/main.cs b/indra/tools/vstool/main.cs deleted file mode 100755 index 1d6b2f14d15..00000000000 --- a/indra/tools/vstool/main.cs +++ /dev/null @@ -1,733 +0,0 @@ -// Code about getting running instances visual studio -// was borrowed from -// http://www.codeproject.com/KB/cs/automatingvisualstudio.aspx - - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using Microsoft.CSharp; - -namespace VSTool -{ - // The MessageFilter class comes from: - // http://msdn.microsoft.com/en-us/library/ms228772(VS.80).aspx - // It allows vstool to get timing error messages from - // visualstudio and handle them. - public class MessageFilter : IOleMessageFilter - { - // - // Class containing the IOleMessageFilter - // thread error-handling functions. - - // Start the filter. - public static void Register() - { - IOleMessageFilter newFilter = new MessageFilter(); - IOleMessageFilter oldFilter = null; - CoRegisterMessageFilter(newFilter, out oldFilter); - } - - // Done with the filter, close it. - public static void Revoke() - { - IOleMessageFilter oldFilter = null; - CoRegisterMessageFilter(null, out oldFilter); - } - - // - // IOleMessageFilter functions. - // Handle incoming thread requests. - int IOleMessageFilter.HandleInComingCall(int dwCallType, - System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr - lpInterfaceInfo) - { - //Return the flag SERVERCALL_ISHANDLED. - return 0; - } - - // Thread call was rejected, so try again. - int IOleMessageFilter.RetryRejectedCall(System.IntPtr - hTaskCallee, int dwTickCount, int dwRejectType) - { - if (dwRejectType == 2) - // flag = SERVERCALL_RETRYLATER. - { - // Retry the thread call immediately if return >=0 & - // <100. - return 99; - } - // Too busy; cancel call. - return -1; - } - - int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee, - int dwTickCount, int dwPendingType) - { - //Return the flag PENDINGMSG_WAITDEFPROCESS. - return 2; - } - - // Implement the IOleMessageFilter interface. - [DllImport("Ole32.dll")] - private static extern int - CoRegisterMessageFilter(IOleMessageFilter newFilter, out - IOleMessageFilter oldFilter); - } - - [ComImport(), Guid("00000016-0000-0000-C000-000000000046"), - InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] - interface IOleMessageFilter - { - [PreserveSig] - int HandleInComingCall( - int dwCallType, - IntPtr hTaskCaller, - int dwTickCount, - IntPtr lpInterfaceInfo); - - [PreserveSig] - int RetryRejectedCall( - IntPtr hTaskCallee, - int dwTickCount, - int dwRejectType); - - [PreserveSig] - int MessagePending( - IntPtr hTaskCallee, - int dwTickCount, - int dwPendingType); - } - - class ViaCOM - { - public static object GetProperty(object from_obj, string prop_name) - { - try - { - Type objType = from_obj.GetType(); - return objType.InvokeMember( - prop_name, - BindingFlags.GetProperty, null, - from_obj, - null); - } - catch (Exception e) - { - Console.WriteLine("Error getting property: \"{0}\"", prop_name); - Console.WriteLine(e.Message); - throw e; - } - } - - public static object SetProperty(object from_obj, string prop_name, object new_value) - { - try - { - object[] args = { new_value }; - Type objType = from_obj.GetType(); - return objType.InvokeMember( - prop_name, - BindingFlags.DeclaredOnly | - BindingFlags.Public | - BindingFlags.NonPublic | - BindingFlags.Instance | - BindingFlags.SetProperty, - null, - from_obj, - args); - } - catch (Exception e) - { - Console.WriteLine("Error setting property: \"{0}\"", prop_name); - Console.WriteLine(e.Message); - throw e; - } - } - - public static object CallMethod(object from_obj, string method_name, params object[] args) - { - try - { - Type objType = from_obj.GetType(); - return objType.InvokeMember( - method_name, - BindingFlags.DeclaredOnly | - BindingFlags.Public | - BindingFlags.NonPublic | - BindingFlags.Instance | - BindingFlags.InvokeMethod, - null, - from_obj, - args); - } - catch (Exception e) - { - Console.WriteLine("Error calling method \"{0}\"", method_name); - Console.WriteLine(e.Message); - throw e; - } - } - }; - - /// - /// The main entry point class for VSTool. - /// - class VSToolMain - { - #region Interop imports - [DllImport("ole32.dll")] - public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot); - - [DllImport("ole32.dll")] - public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc); - #endregion - - static System.Boolean ignore_case = true; - - static string solution_name = null; - static bool use_new_vs = false; - static Hashtable projectDict = new Hashtable(); - static string startup_project = null; - static string config = null; - - static object dte = null; - static object solution = null; - - /// - /// The main entry point for the application. - /// - [STAThread] - static int Main(string[] args) - { - int retVal = 0; - bool need_save = false; - - try - { - parse_command_line(args); - - Console.WriteLine("Editing solution: {0}", solution_name); - - bool found_open_solution = GetDTEAndSolution(); - - if (dte == null || solution == null) - { - retVal = 1; - } - else - { - MessageFilter.Register(); - - // Walk through all of the projects in the solution - // and list the type of each project. - foreach (DictionaryEntry p in projectDict) - { - string project_name = (string)p.Key; - string working_dir = (string)p.Value; - if (SetProjectWorkingDir(solution, project_name, working_dir)) - { - need_save = true; - } - } - - if (config != null) - { - need_save = SetActiveConfig(config); - } - - if (startup_project != null) - { - need_save = SetStartupProject(startup_project); - } - - if (need_save) - { - if (found_open_solution == false) - { - ViaCOM.CallMethod(solution, "Close", null); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e.Message); - retVal = 1; - } - finally - { - if (solution != null) - { - Marshal.ReleaseComObject(solution); - solution = null; - } - - if (dte != null) - { - Marshal.ReleaseComObject(dte); - dte = null; - } - - MessageFilter.Revoke(); - } - return retVal; - } - - public static bool parse_command_line(string[] args) - { - string options_desc = - "--solution : MSVC solution name. (required)\n" + - "--use_new_vs : Ignore running versions of visual studio.\n" + - "--workingdir : Set working dir of a VC project.\n" + - "--config : Set the active config for the solution.\n" + - "--startup : Set the startup project for the solution.\n"; - - try - { - // Command line param parsing loop. - int i = 0; - for (; i < args.Length; ++i) - { - if ("--solution" == args[i]) - { - if (solution_name != null) - { - throw new ApplicationException("Found second --solution option"); - } - solution_name = args[++i]; - } - else if ("--use_new_vs" == args[i]) - { - use_new_vs = true; - } - - else if ("--workingdir" == args[i]) - { - string project_name = args[++i]; - string working_dir = args[++i]; - projectDict.Add(project_name, working_dir); - } - else if ("--config" == args[i]) - { - if (config != null) - { - throw new ApplicationException("Found second --config option"); - } - config = args[++i]; - } - else if ("--startup" == args[i]) - { - if (startup_project != null) - { - throw new ApplicationException("Found second --startup option"); - } - startup_project = args[++i]; - } - else - { - throw new ApplicationException("Found unrecognized token on command line: " + args[i]); - } - } - - if (solution_name == null) - { - throw new ApplicationException("The --solution option is required."); - } - } - catch(ApplicationException e) - { - - Console.WriteLine("Oops! " + e.Message); - Console.Write("Command line:"); - foreach (string arg in args) - { - Console.Write(" " + arg); - } - Console.Write("\n\n"); - Console.WriteLine("VSTool command line usage"); - Console.Write(options_desc); - throw e; - } - return true; - } - - public static bool GetDTEAndSolution() - { - bool found_open_solution = true; - - Console.WriteLine("Looking for existing VisualStudio instance..."); - - // Get an instance of the currently running Visual Studio .NET IDE. - // dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.7.1"); - string full_solution_name = System.IO.Path.GetFullPath(solution_name); - if (false == use_new_vs) - { - dte = GetIDEInstance(full_solution_name); - } - - if (dte == null) - { - try - { - Console.WriteLine(" Didn't find open solution, starting new background VisualStudio instance..."); - Console.WriteLine(" Reading .sln file version..."); - string version = GetSolutionVersion(full_solution_name); - - Console.WriteLine(" Using version: {0}...", version); - string progid = GetVSProgID(version); - - Type objType = Type.GetTypeFromProgID(progid); - dte = System.Activator.CreateInstance(objType); - Console.WriteLine(" Reading solution: \"{0}\"", full_solution_name); - - solution = ViaCOM.GetProperty(dte, "Solution"); - object[] openArgs = { full_solution_name }; - ViaCOM.CallMethod(solution, "Open", openArgs); - } - catch (Exception e) - { - Console.WriteLine(e.Message); - Console.WriteLine("Quitting do to error opening: {0}", full_solution_name); - solution = null; - dte = null; - return found_open_solution; - } - found_open_solution = false; - } - - if (solution == null) - { - solution = ViaCOM.GetProperty(dte, "Solution"); - } - - return found_open_solution; - } - - /// - /// Get the DTE object for the instance of Visual Studio IDE that has - /// the specified solution open. - /// - /// The absolute filename of the solution - /// Corresponding DTE object or null if no such IDE is running - public static object GetIDEInstance( string solutionFile ) - { - Hashtable runningInstances = GetIDEInstances( true ); - IDictionaryEnumerator enumerator = runningInstances.GetEnumerator(); - - while ( enumerator.MoveNext() ) - { - try - { - object ide = enumerator.Value; - if (ide != null) - { - object sol = ViaCOM.GetProperty(ide, "Solution"); - if (0 == string.Compare((string)ViaCOM.GetProperty(sol, "FullName"), solutionFile, ignore_case)) - { - return ide; - } - } - } - catch{} - } - - return null; - } - - /// - /// Get a table of the currently running instances of the Visual Studio .NET IDE. - /// - /// Only return instances that have opened a solution - /// A hashtable mapping the name of the IDE in the running object table to the corresponding DTE object - public static Hashtable GetIDEInstances( bool openSolutionsOnly ) - { - Hashtable runningIDEInstances = new Hashtable(); - Hashtable runningObjects = GetRunningObjectTable(); - - IDictionaryEnumerator rotEnumerator = runningObjects.GetEnumerator(); - while ( rotEnumerator.MoveNext() ) - { - string candidateName = (string) rotEnumerator.Key; - if (!candidateName.StartsWith("!VisualStudio.DTE")) - continue; - - object ide = rotEnumerator.Value; - if (ide == null) - continue; - - if (openSolutionsOnly) - { - try - { - object sol = ViaCOM.GetProperty(ide, "Solution"); - string solutionFile = (string)ViaCOM.GetProperty(sol, "FullName"); - if (solutionFile != String.Empty) - { - runningIDEInstances[ candidateName ] = ide; - } - } - catch {} - } - else - { - runningIDEInstances[ candidateName ] = ide; - } - } - return runningIDEInstances; - } - - /// - /// Get a snapshot of the running object table (ROT). - /// - /// A hashtable mapping the name of the object in the ROT to the corresponding object - [STAThread] - public static Hashtable GetRunningObjectTable() - { - Hashtable result = new Hashtable(); - - int numFetched = 0; - IRunningObjectTable runningObjectTable; - IEnumMoniker monikerEnumerator; - IMoniker[] monikers = new IMoniker[1]; - - GetRunningObjectTable(0, out runningObjectTable); - runningObjectTable.EnumRunning(out monikerEnumerator); - monikerEnumerator.Reset(); - - while (monikerEnumerator.Next(1, monikers, new IntPtr(numFetched)) == 0) - { - IBindCtx ctx; - CreateBindCtx(0, out ctx); - - string runningObjectName; - monikers[0].GetDisplayName(ctx, null, out runningObjectName); - - object runningObjectVal; - runningObjectTable.GetObject( monikers[0], out runningObjectVal); - - result[ runningObjectName ] = runningObjectVal; - } - - return result; - } - - public static string GetSolutionVersion(string solutionFullFileName) - { - string version; - System.IO.StreamReader solutionStreamReader = null; - string firstLine; - string format; - - try - { - solutionStreamReader = new System.IO.StreamReader(solutionFullFileName); - do - { - firstLine = solutionStreamReader.ReadLine(); - } - while (firstLine == ""); - - format = firstLine.Substring(firstLine.LastIndexOf(" ")).Trim(); - - switch(format) - { - case "7.00": - version = "VC70"; - break; - - case "8.00": - version = "VC71"; - break; - - case "9.00": - version = "VC80"; - break; - - case "10.00": - version = "VC90"; - break; - - case "11.00": - version = "VC100"; - break; - - case "12.00": - version = "VC150"; - break; - - default: - throw new ApplicationException("Unknown .sln version: " + format); - } - } - finally - { - if(solutionStreamReader != null) - { - solutionStreamReader.Close(); - } - } - - return version; - } - - public static string GetVSProgID(string version) - { - string progid = null; - switch(version) - { - case "VC70": - progid = "VisualStudio.DTE.7"; - break; - - case "VC71": - progid = "VisualStudio.DTE.7.1"; - break; - - case "VC80": - progid = "VisualStudio.DTE.8.0"; - break; - - case "VC90": - progid = "VisualStudio.DTE.9.0"; - break; - - case "VC100": - progid = "VisualStudio.DTE.10.0"; - break; - - case "VC120": - progid = "VisualStudio.DTE.12.0"; - break; - - case "VC150": - progid = "VisualStudio.DTE.15.0"; - break; - - default: - throw new ApplicationException("Can't handle VS version: " + version); - } - - return progid; - } - - public static bool SetProjectWorkingDir(object sol, string project_name, string working_dir) - { - bool made_change = false; - Console.WriteLine("Looking for project {0}...", project_name); - try - { - object prjs = ViaCOM.GetProperty(sol, "Projects"); - object count = ViaCOM.GetProperty(prjs, "Count"); - for(int i = 1; i <= (int)count; ++i) - { - object[] prjItemArgs = { (object)i }; - object prj = ViaCOM.CallMethod(prjs, "Item", prjItemArgs); - string name = (string)ViaCOM.GetProperty(prj, "Name"); - if (0 == string.Compare(name, project_name, ignore_case)) - { - Console.WriteLine("Found project: {0}", project_name); - Console.WriteLine("Setting working directory"); - - string full_project_name = (string)ViaCOM.GetProperty(prj, "FullName"); - Console.WriteLine(full_project_name); - - // *NOTE:Mani Thanks to incompatibilities between different versions of the - // VCProjectEngine.dll assembly, we can't cast the objects recevied from the DTE to - // the VCProjectEngine types from a different version than the one built - // with. ie, VisualStudio.DTE.7.1 objects can't be converted in a project built - // in VS 8.0. To avoid this problem, we can use the com object interfaces directly, - // without the type casting. Its tedious code, but it seems to work. - - // oCfgs should be assigned to a 'Project.Configurations' collection. - object oCfgs = ViaCOM.GetProperty(ViaCOM.GetProperty(prj, "Object"), "Configurations"); - - // oCount will be assigned to the number of configs present in oCfgs. - object oCount = ViaCOM.GetProperty(oCfgs, "Count"); - - for (int cfgIndex = 1; cfgIndex <= (int)oCount; ++cfgIndex) - { - object[] itemArgs = {(object)cfgIndex}; - object oCfg = ViaCOM.CallMethod(oCfgs, "Item", itemArgs); - object oDebugSettings = ViaCOM.GetProperty(oCfg, "DebugSettings"); - ViaCOM.SetProperty(oDebugSettings, "WorkingDirectory", (object)working_dir); - } - - break; - } - } - made_change = true; - } - catch( Exception e ) - { - Console.WriteLine(e.Message); - Console.WriteLine("Failed to set working dir for project, {0}.", project_name); - } - - return made_change; - } - - public static bool SetStartupProject(string startup_project) - { - bool result = false; - try - { - // You need the 'unique name of the project to set StartupProjects. - // find the project by generic name. - Console.WriteLine("Trying to set \"{0}\" to the startup project", startup_project); - object prjs = ViaCOM.GetProperty(solution, "Projects"); - object count = ViaCOM.GetProperty(prjs, "Count"); - for (int i = 1; i <= (int)count; ++i) - { - object[] itemArgs = { (object)i }; - object prj = ViaCOM.CallMethod(prjs, "Item", itemArgs); - object prjName = ViaCOM.GetProperty(prj, "Name"); - if (0 == string.Compare((string)prjName, startup_project, ignore_case)) - { - object solBuild = ViaCOM.GetProperty(solution, "SolutionBuild"); - ViaCOM.SetProperty(solBuild, "StartupProjects", ViaCOM.GetProperty(prj, "UniqueName")); - Console.WriteLine(" Success!"); - result = true; - break; - } - } - - if (result == false) - { - Console.WriteLine(" Could not find project \"{0}\" in the solution.", startup_project); - } - } - catch (Exception e) - { - Console.WriteLine(" Failed to set the startup project!"); - Console.WriteLine(e.Message); - } - return result; - } - - public static bool SetActiveConfig(string config) - { - bool result = false; - try - { - Console.WriteLine("Trying to set active config to \"{0}\"", config); - object solBuild = ViaCOM.GetProperty(solution, "SolutionBuild"); - object solCfgs = ViaCOM.GetProperty(solBuild, "SolutionConfigurations"); - object[] itemArgs = { (object)config }; - object solCfg = ViaCOM.CallMethod(solCfgs, "Item", itemArgs); - ViaCOM.CallMethod(solCfg, "Activate", null); - Console.WriteLine(" Success!"); - result = true; - } - catch (Exception e) - { - Console.WriteLine(" Failed to set \"{0}\" as the active config.", config); - Console.WriteLine(e.Message); - } - return result; - } - } -} diff --git a/indra/win_crash_logger/README.txt b/indra/win_crash_logger/README.txt deleted file mode 100644 index 6932a8d9c31..00000000000 --- a/indra/win_crash_logger/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -This component is no longer used in Linden Lab builds. -Change requests to support continued use by open source -builds are welcome. From e7c506ba455f32eb8532f5e07bf83419126b5212 Mon Sep 17 00:00:00 2001 From: fmartian Date: Sun, 17 Aug 2025 02:34:50 +0200 Subject: [PATCH 079/145] Fix regex strings for Python 3.12+ Python 3.12 and newer does complain about single backslash in strings and is probably going to treat it as an error in some future version. Make the string constant a raw string. --- indra/newview/viewer_manifest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index cf5e7485132..6991e0c8f2f 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -273,13 +273,13 @@ def extract_names(self,src): # All lines up to and including the first blank line are the file header; skip them lines.reverse() # so that pop will pull from first to last line - while not re.match("\s*$", lines.pop()) : + while not re.match(r"\s*$", lines.pop()) : pass # do nothing # A line that starts with a non-whitespace character is a name; all others describe contributions, so collect the names names = [] for line in lines : - if re.match("\S", line) : + if re.match(r"\S", line) : names.append(line.rstrip()) # It's not fair to always put the same people at the head of the list random.shuffle(names) From 181273f92990e5e37ca8f15c1d7d80d784b1ad77 Mon Sep 17 00:00:00 2001 From: Nicky Date: Sat, 3 Aug 2024 15:42:06 +0200 Subject: [PATCH 080/145] Change another case of a regex sequence needing to be a raw string --- scripts/packages-formatter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/packages-formatter.py b/scripts/packages-formatter.py index 4449111e46b..5d31702e766 100755 --- a/scripts/packages-formatter.py +++ b/scripts/packages-formatter.py @@ -42,7 +42,7 @@ # Coerce stdout encoding to utf-8 as cygwin's will be detected as cp1252 otherwise. _autobuild_env["PYTHONIOENCODING"] = "utf-8" -pkg_line=re.compile('^([\w-]+):\s+(.*)$') +pkg_line=re.compile(r'^([\w-]+):\s+(.*)$') def autobuild(*args): """ From 89c373c20b6032bab819e99cc8ace7b7e6b92360 Mon Sep 17 00:00:00 2001 From: fmartian Date: Mon, 18 Aug 2025 21:16:54 +0200 Subject: [PATCH 081/145] Add new LastModified option to HttpRequest handling (#4563) * Add LastModified: option to the HttpOptions and handle it properly in HttpOpRequest::prepareRequest() * grid_name could be empty if an invalid grid was passed in. --- indra/llcorehttp/_httpoprequest.cpp | 13 +++++++++++++ indra/llcorehttp/httpoptions.cpp | 6 ++++++ indra/llcorehttp/httpoptions.h | 8 ++++++++ indra/newview/llviewernetwork.cpp | 4 ++-- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index 6186e7a308b..081a4d9bac9 100644 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -538,6 +538,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) long sslHostV(0L); long dnsCacheTimeout(-1L); long nobody(0L); + curl_off_t lastModified(0L); if (mReqOptions) { @@ -546,6 +547,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) sslHostV = mReqOptions->getSSLVerifyHost() ? 2L : 0L; dnsCacheTimeout = mReqOptions->getDNSCacheTimeout(); nobody = mReqOptions->getHeadersOnly() ? 1L : 0L; + lastModified = (curl_off_t)mReqOptions->getLastModified(); } check_curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect); @@ -554,6 +556,17 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) check_curl_easy_setopt(mCurlHandle, CURLOPT_NOBODY, nobody); + if (lastModified) + { + check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); +#if (LIBCURL_VERSION_NUM >= 0x073B00) + // requires curl 7.59.0 + check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMEVALUE_LARGE, lastModified); +#else + check_curl_easy_setopt(mCurlHandle, CURLOPT_TIMEVALUE, (long)lastModified); +#endif + } + // The Linksys WRT54G V5 router has an issue with frequent // DNS lookups from LAN machines. If they happen too often, // like for every HTTP request, the router gets annoyed after diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp index d85f6039b1c..5abd28e2112 100644 --- a/indra/llcorehttp/httpoptions.cpp +++ b/indra/llcorehttp/httpoptions.cpp @@ -47,6 +47,7 @@ HttpOptions::HttpOptions() : mVerifyPeer(sDefaultVerifyPeer), mVerifyHost(false), mDNSCacheTimeout(-1L), + mLastModified(0), mNoBody(false) {} @@ -129,6 +130,11 @@ void HttpOptions::setHeadersOnly(bool nobody) } } +void HttpOptions::setLastModified(time_t lastModified) +{ + mLastModified = lastModified; +} + void HttpOptions::setDefaultSSLVerifyPeer(bool verify) { sDefaultVerifyPeer = verify; diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h index 56a28013cb4..fdb277c66ef 100644 --- a/indra/llcorehttp/httpoptions.h +++ b/indra/llcorehttp/httpoptions.h @@ -178,6 +178,13 @@ class HttpOptions : private boost::noncopyable return mNoBody; } + // Default: 0 + void setLastModified(time_t lastModified); + time_t getLastModified() const + { + return mLastModified; + } + /// Sets default behavior for verifying that the name in the /// security certificate matches the name of the host contacted. /// Defaults false if not set, but should be set according to @@ -199,6 +206,7 @@ class HttpOptions : private boost::noncopyable bool mVerifyHost; int mDNSCacheTimeout; bool mNoBody; + time_t mLastModified; static bool sDefaultVerifyPeer; }; // end class HttpOptions diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp index 16ddc2f89c1..f11fa09ce94 100644 --- a/indra/newview/llviewernetwork.cpp +++ b/indra/newview/llviewernetwork.cpp @@ -450,7 +450,7 @@ std::string LLGridManager::getGridLabel(const std::string& grid) { std::string grid_label; std::string grid_name = getGrid(grid); - if (!grid.empty()) + if (!grid_name.empty()) { grid_label = mGridList[grid_name][GRID_LABEL_VALUE].asString(); } @@ -466,7 +466,7 @@ std::string LLGridManager::getGridId(const std::string& grid) { std::string grid_id; std::string grid_name = getGrid(grid); - if (!grid.empty()) + if (!grid_name.empty()) { grid_id = mGridList[grid_name][GRID_ID_VALUE].asString(); } From 77514ebddd68ca47bc3751f0a6e55a83deec79a9 Mon Sep 17 00:00:00 2001 From: Rye Date: Mon, 18 Aug 2025 21:26:20 -0400 Subject: [PATCH 082/145] Fix macOS deprecation warnings --- indra/llprimitive/lldaeloader.cpp | 2 +- indra/llwindow/llopenglview-objc.h | 13 ---- indra/llwindow/llopenglview-objc.mm | 82 ++++++++----------------- indra/llwindow/llwindowmacosx-objc.mm | 3 +- indra/newview/llappdelegate-objc.mm | 2 +- indra/newview/llappviewermacosx-objc.h | 3 - indra/newview/llappviewermacosx-objc.mm | 39 ------------ indra/newview/llfilepicker_mac.mm | 6 +- indra/newview/llfloateremojipicker.cpp | 4 +- indra/newview/llfloateruipreview.cpp | 3 +- 10 files changed, 36 insertions(+), 121 deletions(-) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 07594479028..4c028e71289 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -1314,7 +1314,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do { //Build a joint for the resolver to work with char str[64]={0}; - sprintf(str,"./%s",(*jointIt).first.c_str() ); + snprintf(str, sizeof(str), "./%s",(*jointIt).first.c_str() ); //LL_WARNS()<<"Joint "<< str < + extern BOOL gHiDPISupport; #pragma mark local functions @@ -105,20 +107,6 @@ + (NSScreen *)currentScreenForMouseLocation return screen; } - -- (NSPoint)convertPointToScreenCoordinates:(NSPoint)aPoint -{ - float normalizedX = fabs(fabs(self.frame.origin.x) - fabs(aPoint.x)); - float normalizedY = aPoint.y - self.frame.origin.y; - - return NSMakePoint(normalizedX, normalizedY); -} - -- (NSPoint)flipPoint:(NSPoint)aPoint -{ - return NSMakePoint(aPoint.x, self.frame.size.height - aPoint.y); -} - @end @implementation LLOpenGLView @@ -244,7 +232,7 @@ - (id) initWithSamples:(NSUInteger)samples andVsync:(BOOL)vsync - (id) initWithFrame:(NSRect)frame withSamples:(NSUInteger)samples andVsync:(BOOL)vsync { - [self registerForDraggedTypes:[NSArray arrayWithObject:NSURLPboardType]]; + [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeURL]]; [self initWithFrame:frame]; // Initialize with a default "safe" pixel format that will work with versions dating back to OS X 10.6. @@ -295,13 +283,13 @@ - (id) initWithFrame:(NSRect)frame withSamples:(NSUInteger)samples andVsync:(BOO if (vsync) { GLint value = 1; - [glContext setValues:&value forParameter:NSOpenGLCPSwapInterval]; + [glContext setValues:&value forParameter:NSOpenGLContextParameterSwapInterval]; } else { // supress this error after move to Xcode 7: // error: null passed to a callee that requires a non-null argument [-Werror,-Wnonnull] // Tried using ObjC 'nonnull' keyword as per SO article but didn't build GLint swapInterval=0; - [glContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval]; + [glContext setValues:&swapInterval forParameter:NSOpenGLContextParameterSwapInterval]; } mOldResize = false; @@ -355,13 +343,13 @@ - (void) mouseDown:(NSEvent *)theEvent mMousePos[1] = mPoint.y; // Apparently people still use this? - if ([theEvent modifierFlags] & NSCommandKeyMask && - !([theEvent modifierFlags] & NSControlKeyMask) && - !([theEvent modifierFlags] & NSShiftKeyMask) && - !([theEvent modifierFlags] & NSAlternateKeyMask) && - !([theEvent modifierFlags] & NSAlphaShiftKeyMask) && - !([theEvent modifierFlags] & NSFunctionKeyMask) && - !([theEvent modifierFlags] & NSHelpKeyMask)) + if ([theEvent modifierFlags] & NSEventModifierFlagCommand && + !([theEvent modifierFlags] & NSEventModifierFlagControl) && + !([theEvent modifierFlags] & NSEventModifierFlagShift) && + !([theEvent modifierFlags] & NSEventModifierFlagOption) && + !([theEvent modifierFlags] & NSEventModifierFlagCapsLock) && + !([theEvent modifierFlags] & NSEventModifierFlagFunction) && + !([theEvent modifierFlags] & NSEventModifierFlagHelp)) { callRightMouseDown(mMousePos, [theEvent modifierFlags]); mSimulatedRightClick = true; @@ -511,7 +499,7 @@ - (void) keyDown:(NSEvent *)theEvent if (acceptsText && !mMarkedTextAllowed && - !(mModifiers & (NSControlKeyMask | NSCommandKeyMask)) && // commands don't invoke InputWindow + !(mModifiers & (NSEventModifierFlagControl | NSEventModifierFlagCommand)) && // commands don't invoke InputWindow ![(LLAppDelegate*)[NSApp delegate] romanScript] && ch > ' ' && ch != NSDeleteCharacter && @@ -534,14 +522,14 @@ - (void)flagsChanged:(NSEvent *)theEvent NSInteger mask = 0; switch([theEvent keyCode]) { - case 56: - mask = NSShiftKeyMask; + case kVK_Shift: + mask = NSEventModifierFlagShift; break; - case 58: - mask = NSAlternateKeyMask; + case kVK_Option: + mask = NSEventModifierFlagOption; break; - case 59: - mask = NSControlKeyMask; + case kVK_Control: + mask = NSEventModifierFlagControl; break; default: return; @@ -582,7 +570,7 @@ - (NSDragOperation) draggingEntered:(id)sender pboard = [sender draggingPasteboard]; - if ([[pboard types] containsObject:NSURLPboardType]) + if ([[pboard types] containsObject:NSPasteboardTypeURL]) { if (sourceDragMask & NSDragOperationLink) { NSURL *fileUrl = [[pboard readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]] options:[NSDictionary dictionary]] objectAtIndex:0]; @@ -657,7 +645,7 @@ - (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replaceme }; int string_length = [aString length]; - unichar text[string_length]; + unichar* text = (unichar*)malloc(sizeof(unichar) * string_length); attributedStringInfo segments; // I used 'respondsToSelector:@selector(string)' // to judge aString is an attributed string or not. @@ -675,6 +663,7 @@ - (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replaceme segments.seg_standouts.push_back(true); } setMarkedText(text, selected, replacement, string_length, segments); + free(text); if (string_length > 0) { mHasMarkedText = TRUE; @@ -783,9 +772,9 @@ - (void)insertText:(id)aString replacementRange:(NSRange)replacementRange - (void) insertNewline:(id)sender { - if (!(mModifiers & NSCommandKeyMask) && - !(mModifiers & NSShiftKeyMask) && - !(mModifiers & NSAlternateKeyMask)) + if (!(mModifiers & NSEventModifierFlagCommand) && + !(mModifiers & NSEventModifierFlagShift) && + !(mModifiers & NSEventModifierFlagOption)) { callUnicodeCallback(13, 0); } else { @@ -904,27 +893,6 @@ - (id) init return self; } -- (NSPoint)convertToScreenFromLocalPoint:(NSPoint)point relativeToView:(NSView *)view -{ - NSScreen *currentScreen = [NSScreen currentScreenForMouseLocation]; - if(currentScreen) - { - NSPoint windowPoint = [view convertPoint:point toView:nil]; - NSPoint screenPoint = [[view window] convertBaseToScreen:windowPoint]; - NSPoint flippedScreenPoint = [currentScreen flipPoint:screenPoint]; - flippedScreenPoint.y += [currentScreen frame].origin.y; - - return flippedScreenPoint; - } - - return NSZeroPoint; -} - -- (NSPoint)flipPoint:(NSPoint)aPoint -{ - return NSMakePoint(aPoint.x, self.frame.size.height - aPoint.y); -} - - (BOOL) becomeFirstResponder { callFocus(); diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm index 2e75d309ea6..41b1e3195c4 100644 --- a/indra/llwindow/llwindowmacosx-objc.mm +++ b/indra/llwindow/llwindowmacosx-objc.mm @@ -213,7 +213,8 @@ OSErr setImageCursor(CursorRef ref) NSWindowRef createNSWindow(int x, int y, int width, int height) { LLNSWindow *window = [[LLNSWindow alloc]initWithContentRect:NSMakeRect(x, y, width, height) - styleMask:NSTitledWindowMask | NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTexturedBackgroundWindowMask backing:NSBackingStoreBuffered defer:NO]; + styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable + backing:NSBackingStoreBuffered defer:NO]; [window makeKeyAndOrderFront:nil]; [window setAcceptsMouseMovedEvents:TRUE]; [window setRestorable:FALSE]; // Viewer manages state from own settings diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm index d4b05dde72f..b8fd3dc189f 100644 --- a/indra/newview/llappdelegate-objc.mm +++ b/indra/newview/llappdelegate-objc.mm @@ -372,7 +372,7 @@ @implementation LLApplication - (void)sendEvent:(NSEvent *)event { [super sendEvent:event]; - if ([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask)) + if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSEventModifierFlagCommand)) { [[self keyWindow] sendEvent:event]; } diff --git a/indra/newview/llappviewermacosx-objc.h b/indra/newview/llappviewermacosx-objc.h index d0ae0a7fc2f..3fbf4202f1a 100644 --- a/indra/newview/llappviewermacosx-objc.h +++ b/indra/newview/llappviewermacosx-objc.h @@ -30,9 +30,6 @@ #include #include -//Why? Because BOOL -void launchApplication(const std::string* app_name, const std::vector* args); - void force_ns_sxeption(); #endif // LL_LLAPPVIEWERMACOSX_OBJC_H diff --git a/indra/newview/llappviewermacosx-objc.mm b/indra/newview/llappviewermacosx-objc.mm index 9b6bfe621b6..2ea3f2f1713 100644 --- a/indra/newview/llappviewermacosx-objc.mm +++ b/indra/newview/llappviewermacosx-objc.mm @@ -33,45 +33,6 @@ #include "llappviewermacosx-objc.h" -void launchApplication(const std::string* app_name, const std::vector* args) -{ - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - if (app_name->empty()) return; - - NSMutableString* app_name_ns = [NSMutableString stringWithString:[[NSBundle mainBundle] resourcePath]]; //Path to resource dir - [app_name_ns appendFormat:@"/%@", [NSString stringWithCString:app_name->c_str() - encoding:[NSString defaultCStringEncoding]]]; - - NSMutableArray *args_ns = nil; - args_ns = [[NSMutableArray alloc] init]; - - for (int i=0; i < args->size(); ++i) - { - NSLog(@"Adding string %s", (*args)[i].c_str()); - [args_ns addObject: - [NSString stringWithCString:(*args)[i].c_str() - encoding:[NSString defaultCStringEncoding]]]; - } - - NSTask *task = [[NSTask alloc] init]; - NSBundle *bundle = [NSBundle bundleWithPath:[[NSWorkspace sharedWorkspace] fullPathForApplication:app_name_ns]]; - [task setLaunchPath:[bundle executablePath]]; - [task setArguments:args_ns]; - [task launch]; - -// NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; -// NSURL *url = [NSURL fileURLWithPath:[workspace fullPathForApplication:app_name_ns]]; -// -// NSError *error = nil; -// [workspace launchApplicationAtURL:url options:0 configuration:[NSDictionary dictionaryWithObject:args_ns forKey:NSWorkspaceLaunchConfigurationArguments] error:&error]; - //TODO Handle error - - [pool release]; - return; -} - void force_ns_sxeption() { NSException *exception = [NSException exceptionWithName:@"Forced NSException" reason:nullptr userInfo:nullptr]; diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm index b21bc724fbb..978069457ce 100644 --- a/indra/newview/llfilepicker_mac.mm +++ b/indra/newview/llfilepicker_mac.mm @@ -86,7 +86,7 @@ result = [panel runModal]; - if (result == NSOKButton) + if (result == NSModalResponseOK) { NSArray *filesToOpen = [panel URLs]; int i, count = [filesToOpen count]; @@ -173,7 +173,7 @@ void doLoadDialogModeless(const std::vector* allowed_types, [panel setNameFieldStringValue: fileName]; [panel setDirectoryURL: url]; if([panel runModal] == - NSFileHandlingPanelOKButton) + NSModalResponseOK) { NSURL* url = [panel URL]; NSString* p = [url path]; @@ -211,7 +211,7 @@ void doSaveDialogModeless(const std::string* file, [panel beginWithCompletionHandler:^(NSModalResponse result) { - if (result == NSOKButton) + if (result == NSModalResponseOK) { NSURL* url = [panel URL]; NSString* p = [url path]; diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp index 7e135031031..c5f4a2f0cf4 100644 --- a/indra/newview/llfloateremojipicker.cpp +++ b/indra/newview/llfloateremojipicker.cpp @@ -1284,7 +1284,7 @@ void LLFloaterEmojiPicker::saveState() if (!recentlyUsed.empty()) recentlyUsed += ","; char buffer[32]; - sprintf(buffer, "%u", (U32)emoji); + snprintf(buffer, sizeof(buffer), "%u", (U32)emoji); recentlyUsed += buffer; if (!--maxCount) break; @@ -1301,7 +1301,7 @@ void LLFloaterEmojiPicker::saveState() if (!frequentlyUsed.empty()) frequentlyUsed += ","; char buffer[32]; - sprintf(buffer, "%u:%u", (U32)it.first, (U32)it.second); + snprintf(buffer, sizeof(buffer), "%u:%u", (U32)it.first, (U32)it.second); frequentlyUsed += buffer; if (!--maxCount) break; diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 990a299c504..abffba8ffa9 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -1042,7 +1042,7 @@ void LLFloaterUIPreview::getExecutablePath(const std::vector& filen { CFStringRef executable_cfstr = (CFStringRef)CFDictionaryGetValue(bundleInfoDict, CFSTR("CFBundleExecutable")); // get the name of the actual executable (e.g. TextEdit or firefox-bin) int max_file_length = 256; // (max file name length is 255 in OSX) - char executable_buf[max_file_length]; + char* executable_buf = (char*)malloc(sizeof(char) * max_file_length); if(CFStringGetCString(executable_cfstr, executable_buf, max_file_length, kCFStringEncodingMacRoman)) // convert CFStringRef to char* { executable_path += std::string("/Contents/MacOS/") + std::string(executable_buf); // append path to executable directory and then executable name to exec path @@ -1052,6 +1052,7 @@ void LLFloaterUIPreview::getExecutablePath(const std::vector& filen std::string warning = "Unable to get CString from CFString for executable path"; popupAndPrintWarning(warning); } + free(executable_buf); } else { From d5f748c91c650a2ec534c497b9e098ccb317d70b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 19 Aug 2025 22:17:01 +0300 Subject: [PATCH 083/145] #3223 Trim coroutine queues a little --- indra/llmessage/llcoproceduremanager.cpp | 23 +++++++++++++---------- indra/llmessage/llcoproceduremanager.h | 2 +- indra/llmessage/llexperiencecache.cpp | 3 ++- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index 6a663a8e97c..563dd9459c3 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -50,7 +50,7 @@ static const U32 DEFAULT_POOL_SIZE = 5; // SL-14399: When we teleport to a brand-new simulator, the coprocedure queue // gets absolutely slammed with fetch requests. Make this queue effectively // unlimited. -const U32 LLCoprocedureManager::DEFAULT_QUEUE_SIZE = 1024*1024; +const U32 LLCoprocedureManager::DEFAULT_QUEUE_SIZE = 1024*512; //========================================================================= class LLCoprocedurePool: private boost::noncopyable @@ -58,7 +58,7 @@ class LLCoprocedurePool: private boost::noncopyable public: typedef LLCoprocedureManager::CoProcedure_t CoProcedure_t; - LLCoprocedurePool(const std::string &name, size_t size); + LLCoprocedurePool(const std::string &name, size_t size, size_t queue_size); ~LLCoprocedurePool(); /// Places the coprocedure on the queue for processing. @@ -118,7 +118,7 @@ class LLCoprocedurePool: private boost::noncopyable typedef std::shared_ptr CoprocQueuePtr; std::string mPoolName; - size_t mPoolSize, mActiveCoprocsCount, mPending; + size_t mPoolSize, mQueueSize, mActiveCoprocsCount, mPending; CoprocQueuePtr mPendingCoprocs; LLTempBoundListener mStatusListener; @@ -141,7 +141,7 @@ LLCoprocedureManager::~LLCoprocedureManager() close(); } -void LLCoprocedureManager::initializePool(const std::string &poolName) +void LLCoprocedureManager::initializePool(const std::string &poolName, size_t queue_size) { poolMap_t::iterator it = mPoolMap.find(poolName); @@ -180,7 +180,7 @@ void LLCoprocedureManager::initializePool(const std::string &poolName) LL_WARNS("CoProcMgr") << "LLCoprocedureManager: No setting for \"" << keyName << "\" setting pool size to default of " << size << LL_ENDL; } - poolPtr_t pool(new LLCoprocedurePool(poolName, size)); + poolPtr_t pool(new LLCoprocedurePool(poolName, size, queue_size)); LL_ERRS_IF(!pool, "CoprocedureManager") << "Unable to create pool named \"" << poolName << "\" FATAL!" << LL_ENDL; bool inserted = mPoolMap.emplace(poolName, pool).second; @@ -212,7 +212,8 @@ void LLCoprocedureManager::setPropertyMethods(SettingQuery_t queryfn, SettingUpd mPropertyQueryFn = queryfn; mPropertyDefineFn = updatefn; - initializePool("Upload"); + constexpr size_t UPLOAD_QUEUE_SIZE = 2048; + initializePool("Upload", UPLOAD_QUEUE_SIZE); initializePool("AIS"); // it might be better to have some kind of on-demand initialization for AIS // "ExpCache" pool gets initialized in LLExperienceCache // asset storage pool gets initialized in LLViewerAssetStorage @@ -296,17 +297,19 @@ void LLCoprocedureManager::close(const std::string &pool) } //========================================================================= -LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): +LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size, size_t queue_size): mPoolName(poolName), mPoolSize(size), + mQueueSize(queue_size), mActiveCoprocsCount(0), mPending(0), mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), mCoroMapping() { + llassert_always(mQueueSize > mPoolSize); // queue should be able to fit pool try { - mPendingCoprocs = std::make_shared(LLCoprocedureManager::DEFAULT_QUEUE_SIZE); + mPendingCoprocs = std::make_shared(mQueueSize); // store in our LLTempBoundListener so that when the LLCoprocedurePool is // destroyed, we implicitly disconnect from this LLEventPump // Monitores application status @@ -357,7 +360,7 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): mCoroMapping.insert(CoroAdapterMap_t::value_type(pooledCoro, httpAdapter)); } - LL_INFOS("CoProcMgr") << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items, queue max " << LLCoprocedureManager::DEFAULT_QUEUE_SIZE << LL_ENDL; + LL_INFOS("CoProcMgr") << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items, queue max " << mQueueSize << LL_ENDL; } LLCoprocedurePool::~LLCoprocedurePool() @@ -376,7 +379,7 @@ LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoproced << "\" at " << mPending << LL_ENDL; - if (mPending >= (LLCoprocedureManager::DEFAULT_QUEUE_SIZE - 1)) + if (mPending >= (mQueueSize - 1)) { // If it's all used up (not supposed to happen, // fetched should cap it), we are going to crash diff --git a/indra/llmessage/llcoproceduremanager.h b/indra/llmessage/llcoproceduremanager.h index 6c6e5066545..485333657ca 100644 --- a/indra/llmessage/llcoproceduremanager.h +++ b/indra/llmessage/llcoproceduremanager.h @@ -79,7 +79,7 @@ class LLCoprocedureManager : public LLSingleton < LLCoprocedureManager > void close(); void close(const std::string &pool); - void initializePool(const std::string &poolName); + void initializePool(const std::string &poolName, size_t queue_size = DEFAULT_QUEUE_SIZE); private: diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 83a070df320..78cca47456e 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -110,7 +110,8 @@ void LLExperienceCache::initSingleton() cache_stream >> (*this); } - LLCoprocedureManager::instance().initializePool("ExpCache"); + constexpr size_t CORO_QUEUE_SIZE = 2048; + LLCoprocedureManager::instance().initializePool("ExpCache", CORO_QUEUE_SIZE); LLCoros::instance().launch("LLExperienceCache::idleCoro", boost::bind(&LLExperienceCache::idleCoro, this)); From f0db568bf8d313a00e10c1c4ee4dd7f716a9d987 Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 20 Aug 2025 17:57:06 -0400 Subject: [PATCH 084/145] Rework macOS retina support to remove deprecated code and fix scaled input issues in multimonitor --- indra/llui/llui.cpp | 5 --- indra/llwindow/llopenglview-objc.mm | 32 ++++---------- indra/llwindow/llwindowmacosx-objc.h | 6 +-- indra/llwindow/llwindowmacosx-objc.mm | 63 ++++++++------------------- indra/llwindow/llwindowmacosx.cpp | 19 ++++---- 5 files changed, 38 insertions(+), 87 deletions(-) diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index e36dae39557..38d57205560 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -213,13 +213,8 @@ void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& rem void LLUI::setMousePositionScreen(S32 x, S32 y) { -#if defined(LL_DARWIN) - S32 screen_x = ll_round(((F32)x * getScaleFactor().mV[VX]) / LLView::getWindow()->getSystemUISize()); - S32 screen_y = ll_round(((F32)y * getScaleFactor().mV[VY]) / LLView::getWindow()->getSystemUISize()); -#else S32 screen_x = ll_round((F32)x * getScaleFactor().mV[VX]); S32 screen_y = ll_round((F32)y * getScaleFactor().mV[VY]); -#endif LLView::getWindow()->setCursorPosition(LLCoordGL(screen_x, screen_y).convert()); } diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index 36ae9c60a02..d40e549559f 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -184,7 +184,7 @@ - (void)windowResized:(NSNotification *)notification; { if (!mOldResize) //Maint-3288 { - NSSize dev_sz = gHiDPISupport ? [self convertSizeToBacking:[self frame].size] : [self frame].size; + NSSize dev_sz = [self convertSizeToBacking:[self frame].size]; callResize(dev_sz.width, dev_sz.height); } } @@ -338,10 +338,6 @@ - (CGLPixelFormatObj*)getCGLPixelFormatObj - (void) mouseDown:(NSEvent *)theEvent { - NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; - mMousePos[0] = mPoint.x; - mMousePos[1] = mPoint.y; - // Apparently people still use this? if ([theEvent modifierFlags] & NSEventModifierFlagCommand && !([theEvent modifierFlags] & NSEventModifierFlagControl) && @@ -370,7 +366,7 @@ - (void) mouseUp:(NSEvent *)theEvent callRightMouseUp(mMousePos, [theEvent modifierFlags]); mSimulatedRightClick = false; } else { - NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; + NSPoint mPoint = [self convertPointToBacking:[theEvent locationInWindow]]; mMousePos[0] = mPoint.x; mMousePos[1] = mPoint.y; callLeftMouseUp(mMousePos, [theEvent modifierFlags]); @@ -379,32 +375,26 @@ - (void) mouseUp:(NSEvent *)theEvent - (void) rightMouseDown:(NSEvent *)theEvent { - NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; - mMousePos[0] = mPoint.x; - mMousePos[1] = mPoint.y; callRightMouseDown(mMousePos, [theEvent modifierFlags]); } - (void) rightMouseUp:(NSEvent *)theEvent { - NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; - mMousePos[0] = mPoint.x; - mMousePos[1] = mPoint.y; callRightMouseUp(mMousePos, [theEvent modifierFlags]); } - (void)mouseMoved:(NSEvent *)theEvent { - NSPoint dev_delta = gHiDPISupport ? [self convertPointToBacking:NSMakePoint([theEvent deltaX], [theEvent deltaY])] : NSMakePoint([theEvent deltaX], [theEvent deltaY]); + NSPoint dev_delta = [self convertPointToBacking:NSMakePoint([theEvent deltaX], [theEvent deltaY])]; float mouseDeltas[] = { float(dev_delta.x), float(dev_delta.y) }; - + callDeltaUpdate(mouseDeltas, 0); - - NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; + + NSPoint mPoint = [self convertPointToBacking:[theEvent locationInWindow]]; mMousePos[0] = mPoint.x; mMousePos[1] = mPoint.y; callMouseMoved(mMousePos, 0); @@ -419,7 +409,7 @@ - (void) mouseDragged:(NSEvent *)theEvent // The old CoreGraphics APIs we previously relied on are now flagged as obsolete. // NSEvent isn't obsolete, and provides us with the correct deltas. - NSPoint dev_delta = gHiDPISupport ? [self convertPointToBacking:NSMakePoint([theEvent deltaX], [theEvent deltaY])] : NSMakePoint([theEvent deltaX], [theEvent deltaY]); + NSPoint dev_delta = [self convertPointToBacking:NSMakePoint([theEvent deltaX], [theEvent deltaY])]; float mouseDeltas[] = { float(dev_delta.x), @@ -428,7 +418,7 @@ - (void) mouseDragged:(NSEvent *)theEvent callDeltaUpdate(mouseDeltas, 0); - NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; + NSPoint mPoint = [self convertPointToBacking:[theEvent locationInWindow]]; mMousePos[0] = mPoint.x; mMousePos[1] = mPoint.y; callMouseDragged(mMousePos, 0); @@ -436,17 +426,11 @@ - (void) mouseDragged:(NSEvent *)theEvent - (void) otherMouseDown:(NSEvent *)theEvent { - NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; - mMousePos[0] = mPoint.x; - mMousePos[1] = mPoint.y; callOtherMouseDown(mMousePos, [theEvent modifierFlags], [theEvent buttonNumber]); } - (void) otherMouseUp:(NSEvent *)theEvent { - NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; - mMousePos[0] = mPoint.x; - mMousePos[1] = mPoint.y; callOtherMouseUp(mMousePos, [theEvent modifierFlags], [theEvent buttonNumber]); } diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index d9d8bfce1fe..fa0b8b8f382 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -111,16 +111,14 @@ void glSwapBuffers(void* context); CGLContextObj getCGLContextObj(GLViewRef view); unsigned long getVramSize(GLViewRef view); float getDeviceUnitSize(GLViewRef view); -CGPoint getContentViewBoundsPosition(NSWindowRef window); -CGSize getContentViewBoundsSize(NSWindowRef window); -CGSize getDeviceContentViewSize(NSWindowRef window, GLViewRef view); +CGRect getContentViewRect(NSWindowRef window); +CGRect getBackingViewRect(NSWindowRef window, GLViewRef view); void getWindowSize(NSWindowRef window, float* size); void setWindowSize(NSWindowRef window, int width, int height); void getCursorPos(NSWindowRef window, float* pos); void makeWindowOrderFront(NSWindowRef window); void convertScreenToWindow(NSWindowRef window, float *coord); void convertWindowToScreen(NSWindowRef window, float *coord); -void convertScreenToView(NSWindowRef window, float *coord); void convertRectToScreen(NSWindowRef window, float *coord); void convertRectFromScreen(NSWindowRef window, float *coord); void setWindowPos(NSWindowRef window, float* pos); diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm index 41b1e3195c4..40341ea2e3b 100644 --- a/indra/llwindow/llwindowmacosx-objc.mm +++ b/indra/llwindow/llwindowmacosx-objc.mm @@ -259,19 +259,14 @@ float getDeviceUnitSize(GLViewRef view) return [(LLOpenGLView*)view convertSizeToBacking:NSMakeSize(1, 1)].width; } -CGPoint getContentViewBoundsPosition(NSWindowRef window) +CGRect getContentViewRect(NSWindowRef window) { - return [[(LLNSWindow*)window contentView] bounds].origin; + return [[(LLNSWindow*)window contentView] bounds]; } -CGSize getContentViewBoundsSize(NSWindowRef window) +CGRect getBackingViewRect(NSWindowRef window, GLViewRef view) { - return [[(LLNSWindow*)window contentView] bounds].size; -} - -CGSize getDeviceContentViewSize(NSWindowRef window, GLViewRef view) -{ - return [(NSOpenGLView*)view convertRectToBacking:[[(LLNSWindow*)window contentView] bounds]].size; + return [(NSOpenGLView*)view convertRectToBacking:[[(LLNSWindow*)window contentView] bounds]]; } void getWindowSize(NSWindowRef window, float* size) @@ -314,9 +309,7 @@ void makeWindowOrderFront(NSWindowRef window) void convertScreenToWindow(NSWindowRef window, float *coord) { - NSRect point; - point.origin.x = coord[0]; - point.origin.y = coord[1]; + NSRect point = NSMakeRect(coord[0], coord[1], 0,0); point = [(LLNSWindow*)window convertRectFromScreen:point]; coord[0] = point.origin.x; coord[1] = point.origin.y; @@ -324,28 +317,18 @@ void convertScreenToWindow(NSWindowRef window, float *coord) void convertRectToScreen(NSWindowRef window, float *coord) { - NSRect point; - point.origin.x = coord[0]; - point.origin.y = coord[1]; - point.size.width = coord[2]; - point.size.height = coord[3]; - - point = [(LLNSWindow*)window convertRectToScreen:point]; - - coord[0] = point.origin.x; - coord[1] = point.origin.y; - coord[2] = point.size.width; - coord[3] = point.size.height; + NSRect rect = NSMakeRect(coord[0], coord[1], coord[2], coord[3]);; + rect = [(LLNSWindow*)window convertRectToScreen:rect]; + + coord[0] = rect.origin.x; + coord[1] = rect.origin.y; + coord[2] = rect.size.width; + coord[3] = rect.size.height; } void convertRectFromScreen(NSWindowRef window, float *coord) { - NSRect point; - point.origin.x = coord[0]; - point.origin.y = coord[1]; - point.size.width = coord[2]; - point.size.height = coord[3]; - + NSRect point = NSMakeRect(coord[0], coord[1], coord[2], coord[3]); point = [(LLNSWindow*)window convertRectFromScreen:point]; coord[0] = point.origin.x; @@ -354,23 +337,13 @@ void convertRectFromScreen(NSWindowRef window, float *coord) coord[3] = point.size.height; } -void convertScreenToView(NSWindowRef window, float *coord) -{ - NSRect point; - point.origin.x = coord[0]; - point.origin.y = coord[1]; - point.origin = [(LLNSWindow*)window convertScreenToBase:point.origin]; - point.origin = [[(LLNSWindow*)window contentView] convertPoint:point.origin fromView:nil]; -} - void convertWindowToScreen(NSWindowRef window, float *coord) { - NSPoint point; - point.x = coord[0]; - point.y = coord[1]; - point = [(LLNSWindow*)window convertToScreenFromLocalPoint:point relativeToView:[(LLNSWindow*)window contentView]]; - coord[0] = point.x; - coord[1] = point.y; + NSRect rect = NSMakeRect(coord[0], coord[1], 0, 0); + rect = [(LLNSWindow*)window convertRectToScreen:rect]; + + coord[0] = rect.origin.x; + coord[1] = [[NSScreen screens][0] frame].size.height - rect.origin.y; } void closeWindow(NSWindowRef window) diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index dadbc83f45e..b3f96978675 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -985,7 +985,7 @@ bool LLWindowMacOSX::getPosition(LLCoordScreen *position) } else if(mWindow) { - const CGPoint & pos = getContentViewBoundsPosition(mWindow); + CGPoint pos = getContentViewRect(mWindow).origin; position->mX = pos.x; position->mY = pos.y; @@ -1012,7 +1012,7 @@ bool LLWindowMacOSX::getSize(LLCoordScreen *size) } else if(mWindow) { - const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); + CGSize sz = getBackingViewRect(mWindow, mGLView).size; size->mX = sz.width; size->mY = sz.height; @@ -1038,7 +1038,7 @@ bool LLWindowMacOSX::getSize(LLCoordWindow *size) } else if(mWindow) { - const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); + CGSize sz = getBackingViewRect(mWindow, mGLView).size; size->mX = sz.width; size->mY = sz.height; @@ -1485,8 +1485,9 @@ bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) convertScreenToWindow(mWindow, mouse_point); - to->mX = mouse_point[0]; - to->mY = mouse_point[1]; + float scale_factor = getSystemUISize(); + to->mX = mouse_point[0] * scale_factor; + to->mY = mouse_point[1] * scale_factor; return true; } @@ -1498,9 +1499,9 @@ bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) if(mWindow) { float mouse_point[2]; - - mouse_point[0] = from.mX; - mouse_point[1] = from.mY; + float scale_factor = getSystemUISize(); + mouse_point[0] = from.mX / scale_factor; + mouse_point[1] = from.mY / scale_factor; convertWindowToScreen(mWindow, mouse_point); @@ -2637,7 +2638,7 @@ MASK LLWindowMacOSX::modifiersToMask(S16 modifiers) F32 LLWindowMacOSX::getSystemUISize() { - return gHiDPISupport ? ::getDeviceUnitSize(mGLView) : LLWindow::getSystemUISize(); + return ::getDeviceUnitSize(mGLView); } #if LL_OS_DRAGDROP_ENABLED From fdf404c46165d4faa57678cc3b9ff6af4dda4a01 Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 20 Aug 2025 18:05:50 -0400 Subject: [PATCH 085/145] Speed up build and configure by only generating top level xcode project and enabling dependency buildsystem optimization --- indra/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 69dfe50553a..62f8e0ff8bf 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -35,6 +35,8 @@ if (NOT DEFINED CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 20) endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_OPTIMIZE_DEPENDENCIES ON) +set(CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY ON) include(Variables) include(BuildVersion) From f5423d4517e2e5fb747b2141cb9b71780662c435 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 21 Aug 2025 01:27:08 +0300 Subject: [PATCH 086/145] #4570 Attemp to send logout message when lost network To not leave a ghost behind and for faster reconnect --- indra/newview/llappviewer.cpp | 22 ++++++++++++++++++++++ indra/newview/llappviewer.h | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3eb0479341b..ac9464d86ed 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4530,6 +4530,7 @@ void LLAppViewer::forceDisconnect(const std::string& mesg) } else { + sendSimpleLogoutRequest(); args["MESSAGE"] = big_reason; LLNotificationsUtil::add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect ); } @@ -5310,6 +5311,27 @@ void LLAppViewer::sendLogoutRequest() } } +void LLAppViewer::sendSimpleLogoutRequest() +{ + if (!mLogoutRequestSent && gMessageSystem) + { + gLogoutInProgress = true; + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_LogoutRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); + + LL_INFOS("Agent") << "Logging out as agent: " << gAgent.getID() << " Session: " << gAgent.getSessionID() << LL_ENDL; + + gLogoutTimer.reset(); + gLogoutMaxTime = LOGOUT_REQUEST_TIME; + mLogoutRequestSent = true; + } +} + void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp) { if (!regionp || !regionp->capabilitiesReceived()) diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 132d7bfe25b..e7de2d9b28f 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -310,6 +310,10 @@ class LLAppViewer : public LLApp void sendLogoutRequest(); void disconnectViewer(); + // Does not create a marker file. For lost network case, + // to at least attempt to remove the ghost from the world. + void sendSimpleLogoutRequest(); + // *FIX: the app viewer class should be some sort of singleton, no? // Perhaps its child class is the singleton and this should be an abstract base. static LLAppViewer* sInstance; From 2a3fa6964507f133a599649efe58e350efc43fdf Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 21 Aug 2025 19:30:52 +0300 Subject: [PATCH 087/145] #4591 Crash at LLWearableItemsList's ContextMenu --- indra/newview/llwearableitemslist.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 5fb22184c3d..cc593fe7b4d 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -994,8 +994,11 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu LLUUID linked_id = item->getLinkedUUID(); LLViewerInventoryItem* linked_item = gInventory.getItem(linked_id); - can_favorite |= !linked_item->getIsFavorite(); - can_unfavorite |= linked_item->getIsFavorite(); + if (linked_item) + { + can_favorite |= !linked_item->getIsFavorite(); + can_unfavorite |= linked_item->getIsFavorite(); + } if (is_worn) { From e5ccf7a2a3288569eab210e9d29aeb9dd7964880 Mon Sep 17 00:00:00 2001 From: Rye Date: Fri, 22 Aug 2025 03:08:28 -0400 Subject: [PATCH 088/145] Remove dead code for macos versions 10.6 and older --- indra/llwindow/llopenglview-objc.h | 4 ---- indra/llwindow/llopenglview-objc.mm | 26 +++----------------------- indra/llwindow/llwindow.h | 1 - indra/llwindow/llwindowmacosx-objc.h | 1 - indra/llwindow/llwindowmacosx-objc.mm | 5 ----- indra/llwindow/llwindowmacosx.h | 3 --- indra/newview/llappviewer.cpp | 11 ----------- 7 files changed, 3 insertions(+), 48 deletions(-) diff --git a/indra/llwindow/llopenglview-objc.h b/indra/llwindow/llopenglview-objc.h index a528d7547f1..028549b82ec 100644 --- a/indra/llwindow/llopenglview-objc.h +++ b/indra/llwindow/llopenglview-objc.h @@ -42,7 +42,6 @@ unsigned int mMarkedTextLength; bool mMarkedTextAllowed; bool mSimulatedRightClick; - bool mOldResize; } - (id) initWithSamples:(NSUInteger)samples; - (id) initWithSamples:(NSUInteger)samples andVsync:(BOOL)vsync; @@ -50,8 +49,6 @@ - (void)commitCurrentPreedit; -- (void) setOldResize:(bool)oldresize; - // rebuildContext // Destroys and recreates a context with the view's internal format set via setPixelFormat; // Use this in event of needing to rebuild a context for whatever reason, without needing to assign a new pixel format. @@ -68,7 +65,6 @@ - (unsigned long) getVramSize; - (void) allowMarkedTextInput:(bool)allowed; -- (void) viewDidEndLiveResize; @end diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index 58a17227a7d..3808418112a 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -111,16 +111,6 @@ + (NSScreen *)currentScreenForMouseLocation @implementation LLOpenGLView -// Force a high quality update after live resizing -- (void) viewDidEndLiveResize -{ - if (mOldResize) //Maint-3135 - { - NSSize size = [self frame].size; - callResize(size.width, size.height); - } -} - - (unsigned long)getVramSize { CGLRendererInfoObj info = 0; @@ -175,18 +165,10 @@ - (void)viewDidMoveToWindow } } -- (void)setOldResize:(bool)oldresize -{ - mOldResize = oldresize; -} - - (void)windowResized:(NSNotification *)notification; { - if (!mOldResize) //Maint-3288 - { - NSSize dev_sz = [self convertSizeToBacking:[self frame].size]; - callResize(dev_sz.width, dev_sz.height); - } + NSSize dev_sz = [self convertSizeToBacking:[self frame].size]; + callResize(dev_sz.width, dev_sz.height); } - (void)windowWillMiniaturize:(NSNotification *)notification; @@ -291,9 +273,7 @@ - (id) initWithFrame:(NSRect)frame withSamples:(NSUInteger)samples andVsync:(BOO GLint swapInterval=0; [glContext setValues:&swapInterval forParameter:NSOpenGLContextParameterSwapInterval]; } - - mOldResize = false; - + return self; } diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 151028113ae..d0fa16b26a6 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -147,7 +147,6 @@ class LLWindow : public LLInstanceTracker virtual void swapBuffers() = 0; virtual void bringToFront() = 0; virtual void focusClient() { }; // this may not have meaning or be required on other platforms, therefore, it's not abstract - virtual void setOldResize(bool oldresize) { }; // handy coordinate space conversion routines // NB: screen to window and vice verse won't work on width/height coordinate pairs, // as the conversion must take into account left AND right border widths, etc. diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index fa0b8b8f382..b302a705da6 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -100,7 +100,6 @@ bool isCGCursorVisible(); void hideNSCursorTillMove(bool hide); void requestUserAttention(); long showAlert(std::string title, std::string text, int type); -void setResizeMode(bool oldresize, void* glview); NSWindowRef createNSWindow(int x, int y, int width, int height); diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm index 40341ea2e3b..7f871115707 100644 --- a/indra/llwindow/llwindowmacosx-objc.mm +++ b/indra/llwindow/llwindowmacosx-objc.mm @@ -228,11 +228,6 @@ GLViewRef createOpenGLView(NSWindowRef window, unsigned int samples, bool vsync) return glview; } -void setResizeMode(bool oldresize, void* glview) -{ - [(LLOpenGLView *)glview setOldResize:oldresize]; -} - void glSwapBuffers(void* context) { [(NSOpenGLContext*)context flushBuffer]; diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 7de1a40d93d..110c5756d0f 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -174,9 +174,6 @@ class LLWindowMacOSX : public LLWindow bool shouldPostQuit() { return mPostQuit; } - //Satisfy MAINT-3135 and MAINT-3288 with a flag. - /*virtual */ void setOldResize(bool oldresize) override {setResizeMode(oldresize, mGLView); } - private: void restoreGLContext(); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 2c5c7b63483..88f6005dced 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3172,17 +3172,6 @@ bool LLAppViewer::initWindow() LLNotificationsUI::LLNotificationManager::getInstance(); - -#ifdef LL_DARWIN - //Satisfy both MAINT-3135 (OSX 10.6 and earlier) MAINT-3288 (OSX 10.7 and later) - LLOSInfo& os_info = LLOSInfo::instance(); - if (os_info.mMajorVer == 10 && os_info.mMinorVer < 7) - { - if ( os_info.mMinorVer == 6 && os_info.mBuild < 8 ) - gViewerWindow->getWindow()->setOldResize(true); - } -#endif - if (gSavedSettings.getBOOL("WindowMaximized")) { gViewerWindow->getWindow()->maximize(); From a46d4f0f6923080d7c6e7d5267206e8c8d7a6ff9 Mon Sep 17 00:00:00 2001 From: Rye Date: Fri, 22 Aug 2025 03:32:02 -0400 Subject: [PATCH 089/145] Enable deprecation warnings and suppress a small handful that have no modern replacements --- indra/cmake/00-Common.cmake | 2 +- indra/llcommon/llmd5.cpp | 9 +++++++++ indra/llwindow/CMakeLists.txt | 2 +- indra/llwindow/llopenglview-objc.mm | 20 ++++++++++++++++++++ indra/llwindow/llwindowmacosx-objc.mm | 10 ++++++++++ indra/llwindow/llwindowmacosx.cpp | 10 ++++++++++ indra/newview/llviewerwindow.cpp | 8 ++++++++ 7 files changed, 59 insertions(+), 2 deletions(-) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index c1f46a25a39..7ca58c7ea0e 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -184,7 +184,7 @@ if (LINUX OR DARWIN) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") # libstdc++ headers contain deprecated declarations that fail on clang # macOS currently has many deprecated calls - add_compile_options(-Wno-unused-local-typedef -Wno-deprecated-declarations) + add_compile_options(-Wno-unused-local-typedef) endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp index e999b8f597d..c806c0ab2e9 100644 --- a/indra/llcommon/llmd5.cpp +++ b/indra/llcommon/llmd5.cpp @@ -255,6 +255,11 @@ void LLMD5::raw_digest(unsigned char* s) const memcpy(s, digest, 16); /* Flawfinder: ignore */ } +#if LL_DARWIN +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + void LLMD5::hex_digest(char* s) const { if (!finalized) @@ -273,6 +278,10 @@ void LLMD5::hex_digest(char* s) const s[32] = '\0'; } +#if LL_DARWIN +#pragma clang diagnostic push +#endif + std::ostream& operator<<(std::ostream& stream, const LLMD5& context) { char s[33]; /* Flawfinder: ignore */ diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index 01a7c303a9b..08b3df87abe 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -107,7 +107,7 @@ if (DARWIN) llkeyboardmacosx.cpp llwindowmacosx.cpp PROPERTIES - COMPILE_FLAGS "-Wno-deprecated-declarations -fpascal-strings" + COMPILE_FLAGS "-fpascal-strings" ) endif (DARWIN) diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index 3808418112a..f3aa164f921 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -212,6 +212,12 @@ - (id) initWithSamples:(NSUInteger)samples andVsync:(BOOL)vsync return [self initWithFrame:[self bounds] withSamples:samples andVsync:vsync]; } +#if LL_DARWIN +// For setView and opengl deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + - (id) initWithFrame:(NSRect)frame withSamples:(NSUInteger)samples andVsync:(BOOL)vsync { [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeURL]]; @@ -301,6 +307,10 @@ - (BOOL) rebuildContextWithFormat:(NSOpenGLPixelFormat *)format return true; } +#if LL_DARWIN +#pragma clang diagnostic pop +#endif + - (CGLContextObj)getCGLContextObj { NSOpenGLContext *ctx = [self openGLContext]; @@ -647,6 +657,12 @@ - (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replaceme } } +#if LL_DARWIN +// For commitEditing deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + - (void)commitCurrentPreedit { if (mHasMarkedText) @@ -658,6 +674,10 @@ - (void)commitCurrentPreedit } } +#if LL_DARWIN +#pragma clang diagnostic pop +#endif + - (void)unmarkText { [[self inputContext] discardMarkedText]; diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm index 7f871115707..42cd95be5dd 100644 --- a/indra/llwindow/llwindowmacosx-objc.mm +++ b/indra/llwindow/llwindowmacosx-objc.mm @@ -162,11 +162,21 @@ void showNSCursor() [NSCursor unhide]; } +#if LL_DARWIN +// For CGCursorIsVisible no replacement in modern API +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + bool isCGCursorVisible() { return CGCursorIsVisible(); } +#if LL_DARWIN +#pragma clang diagnostic pop +#endif + void hideNSCursorTillMove(bool hide) { [NSCursor setHiddenUntilMouseMoves:hide]; diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index b3f96978675..0e03b4e8835 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1224,6 +1224,12 @@ void LLWindowMacOSX::setMouseClipping( bool b ) adjustCursorDecouple(); } +#if LL_DARWIN +// For CGSetLocalEventsSuppressionInterval there is no replacement in modern API +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) { bool result = false; @@ -1261,6 +1267,10 @@ bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) return result; } +#if LL_DARWIN +#pragma clang diagnostic pop +#endif + bool LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) { float cursor_point[2]; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index fdd75f9c6cd..2f943b4836f 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -784,8 +784,16 @@ class LLDebugText addText(xpos, ypos, "Projection Matrix"); ypos += y_inc; +#if LL_DARWIN +// For sprintf deprecation +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif // View last column is always <0,0,0,1> MATRIX_ROW_F32_TO_STR(gGLModelView, 12,camera_lines[3]); addText(xpos, ypos, std::string(camera_lines[3])); ypos += y_inc; +#if LL_DARWIN +#pragma clang diagnostic pop +#endif MATRIX_ROW_N32_TO_STR(gGLModelView, 8,camera_lines[2]); addText(xpos, ypos, std::string(camera_lines[2])); ypos += y_inc; MATRIX_ROW_N32_TO_STR(gGLModelView, 4,camera_lines[1]); addText(xpos, ypos, std::string(camera_lines[1])); ypos += y_inc; mBackRectCamera2.mTop = ypos + 2; MATRIX_ROW_N32_TO_STR(gGLModelView, 0,camera_lines[0]); addText(xpos, ypos, std::string(camera_lines[0])); ypos += y_inc; From 99ce597b54a9180cff0f8907e94833257b77e263 Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 27 Feb 2025 19:28:01 -0500 Subject: [PATCH 090/145] Fix texture filtering and address mode not updating for vast majority of textures when dirtied --- indra/llrender/llrender.cpp | 22 +++++++++++++++++++--- indra/llrender/llrender.h | 4 ++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index c26e9b15b8a..4f646cdc330 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -207,6 +207,12 @@ void LLTexUnit::bindFast(LLTexture* texture) } glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture); mHasMipMaps = gl_tex->mHasMipMaps; + if (gl_tex->mTexOptionsDirty) + { + gl_tex->mTexOptionsDirty = false; + setTextureAddressModeFast(gl_tex->mAddressMode); + setTextureFilteringOptionFast(gl_tex->mFilterOption); + } } bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind) @@ -461,11 +467,16 @@ void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode) activate(); - glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_S, sGLAddressMode[mode]); - glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_T, sGLAddressMode[mode]); + setTextureAddressModeFast(mode); +} + +void LLTexUnit::setTextureAddressModeFast(eTextureAddressMode mode) +{ + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_S, sGLAddressMode[mode]); + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_T, sGLAddressMode[mode]); if (mCurrTexType == TT_CUBE_MAP) { - glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, sGLAddressMode[mode]); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, sGLAddressMode[mode]); } } @@ -475,6 +486,11 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio gGL.flush(); + setTextureFilteringOptionFast(option); +} + +void LLTexUnit::setTextureFilteringOptionFast(LLTexUnit::eTextureFilterOptions option) +{ if (option == TFO_POINT) { glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_NEAREST); diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 9e68c2dcd12..755aee4bd6f 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -208,11 +208,15 @@ class LLTexUnit // Warning: this stays set for the bound texture forever, // make sure you want to permanently change the address mode for the bound texture. void setTextureAddressMode(eTextureAddressMode mode); + // MUST already be active and bound + void setTextureAddressModeFast(eTextureAddressMode mode); // Sets the filtering options used to sample the texture // Warning: this stays set for the bound texture forever, // make sure you want to permanently change the filtering for the bound texture. void setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option); + // MUST already be active and bound + void setTextureFilteringOptionFast(LLTexUnit::eTextureFilterOptions option); static U32 getInternalType(eTextureType type); From f8a0878c785cdf5fbc146b9498ae126b51909f24 Mon Sep 17 00:00:00 2001 From: Rye Date: Fri, 22 Aug 2025 12:23:45 -0400 Subject: [PATCH 091/145] Fix Apple M GPU crash from nans slipping into the normal buffer by utilizing a non-float format --- indra/newview/pipeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index b18e01c646d..4df8936d4da 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -346,7 +346,7 @@ void validate_framebuffer_object(); bool addDeferredAttachments(LLRenderTarget& target, bool for_impostor = false) { U32 orm = GL_RGBA; - U32 norm = GL_RGBA16F; + U32 norm = GL_RGBA16; U32 emissive = GL_RGB16F; static LLCachedControl has_emissive(gSavedSettings, "RenderEnableEmissiveBuffer", false); From 24aef9a98267ee07f3771f010b9e35de392e8355 Mon Sep 17 00:00:00 2001 From: Rye Date: Fri, 22 Aug 2025 13:12:43 -0400 Subject: [PATCH 092/145] Fix large performance drop when enabling AA on macOS/lower end GPU hardware --- indra/llrender/llimagegl.cpp | 1 + .../shaders/class1/deferred/SMAA.glsl | 16 +++- indra/newview/llgltfmaterialpreviewmgr.cpp | 10 +-- indra/newview/pipeline.cpp | 78 ++++++++++++------- indra/newview/pipeline.h | 3 +- 5 files changed, 72 insertions(+), 36 deletions(-) diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 1db36d91f9e..52738ec626a 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -338,6 +338,7 @@ S32 LLImageGL::dataFormatBits(S32 dataformat) case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac case GL_DEPTH_COMPONENT: return 24; case GL_DEPTH_COMPONENT24: return 24; + case GL_RGBA16: return 64; case GL_R16F: return 16; case GL_RG16F: return 32; case GL_RGB16F: return 48; diff --git a/indra/newview/app_settings/shaders/class1/deferred/SMAA.glsl b/indra/newview/app_settings/shaders/class1/deferred/SMAA.glsl index fdb77cce6ee..58373089653 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/SMAA.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/SMAA.glsl @@ -1351,6 +1351,10 @@ float4 SMAABlendingWeightCalculationPS(float2 texcoord, //----------------------------------------------------------------------------- // Neighborhood Blending Pixel Shader (Third Pass) +vec3 srgb_to_linear(vec3 cs); +vec4 srgb_to_linear4(vec4 cs); +vec3 linear_to_srgb(vec3 cl); + float4 SMAANeighborhoodBlendingPS(float2 texcoord, float4 offset, SMAATexture2D(colorTex), @@ -1369,6 +1373,7 @@ float4 SMAANeighborhoodBlendingPS(float2 texcoord, SMAA_BRANCH if (dot(a, float4(1.0, 1.0, 1.0, 1.0)) < 1e-5) { float4 color = SMAASampleLevelZero(colorTex, texcoord); + color.rgb = srgb_to_linear(color.rgb); #if SMAA_REPROJECTION float2 velocity = SMAA_DECODE_VELOCITY(SMAASampleLevelZero(velocityTex, texcoord)); @@ -1377,6 +1382,7 @@ float4 SMAANeighborhoodBlendingPS(float2 texcoord, color.a = sqrt(5.0 * length(velocity)); #endif + color.rgb = linear_to_srgb(color.rgb); return color; } else { bool h = max(a.x, a.z) > max(a.y, a.w); // max(horizontal) > max(vertical) @@ -1393,8 +1399,13 @@ float4 SMAANeighborhoodBlendingPS(float2 texcoord, // We exploit bilinear filtering to mix current pixel with the chosen // neighbor: - float4 color = blendingWeight.x * SMAASampleLevelZero(colorTex, blendingCoord.xy); - color += blendingWeight.y * SMAASampleLevelZero(colorTex, blendingCoord.zw); + float4 color = SMAASampleLevelZero(colorTex, blendingCoord.xy); + color.rgb = srgb_to_linear(color.rgb); + color = blendingWeight.x * color; + + float4 color2 = SMAASampleLevelZero(colorTex, blendingCoord.zw); + color2.rgb = srgb_to_linear(color2.rgb); + color += blendingWeight.y * color2; #if SMAA_REPROJECTION // Antialias velocity for proper reprojection in a later stage: @@ -1405,6 +1416,7 @@ float4 SMAANeighborhoodBlendingPS(float2 texcoord, color.a = sqrt(5.0 * length(velocity)); #endif + color.rgb = linear_to_srgb(color.rgb); return color; } } diff --git a/indra/newview/llgltfmaterialpreviewmgr.cpp b/indra/newview/llgltfmaterialpreviewmgr.cpp index da1f1a466f7..5a6e9565aec 100644 --- a/indra/newview/llgltfmaterialpreviewmgr.cpp +++ b/indra/newview/llgltfmaterialpreviewmgr.cpp @@ -523,12 +523,12 @@ bool LLGLTFPreviewTexture::render() gPipeline.copyScreenSpaceReflections(&screen, &gPipeline.mSceneMap); gPipeline.generateLuminance(&screen, &gPipeline.mLuminanceMap); gPipeline.generateExposure(&gPipeline.mLuminanceMap, &gPipeline.mExposureMap, /*use_history = */ false); - gPipeline.gammaCorrect(&screen, &gPipeline.mPostMap); + gPipeline.gammaCorrect(&screen, &gPipeline.mPostPingMap); LLVertexBuffer::unbind(); - gPipeline.generateGlow(&gPipeline.mPostMap); - gPipeline.combineGlow(&gPipeline.mPostMap, &screen); - gPipeline.renderDoF(&screen, &gPipeline.mPostMap); - gPipeline.applyFXAA(&gPipeline.mPostMap, &screen); + gPipeline.generateGlow(&gPipeline.mPostPingMap); + gPipeline.combineGlow(&gPipeline.mPostPingMap, &screen); + gPipeline.renderDoF(&screen, &gPipeline.mPostPingMap); + gPipeline.applyFXAA(&gPipeline.mPostPingMap, &screen); // *HACK: Restore mExposureMap (it will be consumed by generateExposure next frame) gPipeline.mExposureMap.swapFBORefs(gPipeline.mLastExposure); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 4df8936d4da..0120e1487ea 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -856,12 +856,12 @@ bool LLPipeline::allocateScreenBufferInternal(U32 resX, U32 resY) GLuint screenFormat = hdr ? GL_RGBA16F : GL_RGBA; - if (!mRT->screen.allocate(resX, resY, GL_RGBA16F)) return false; + if (!mRT->screen.allocate(resX, resY, screenFormat)) return false; mRT->deferredScreen.shareDepthBuffer(mRT->screen); - if (shadow_detail > 0 || ssao || RenderDepthOfField) - { //only need mRT->deferredLight for shadows OR ssao OR dof + if (hdr || shadow_detail > 0 || ssao || RenderDepthOfField) + { //only need mRT->deferredLight for hdr OR shadows OR ssao OR dof if (!mRT->deferredLight.allocate(resX, resY, screenFormat)) return false; } else @@ -907,7 +907,8 @@ bool LLPipeline::allocateScreenBufferInternal(U32 resX, U32 resY) mSceneMap.release(); } - mPostMap.allocate(resX, resY, screenFormat); + mPostPingMap.allocate(resX, resY, GL_RGBA); + mPostPongMap.allocate(resX, resY, GL_RGBA); // The water exclusion mask needs its own depth buffer so we can take care of the problem of multiple water planes. // Should we ever make water not just a plane, it also aids with that as well as the water planes will be rendered into the mask. @@ -1179,7 +1180,8 @@ void LLPipeline::releaseGLBuffers() mWaterExclusionMask.release(); - mPostMap.release(); + mPostPingMap.release(); + mPostPongMap.release(); mFXAAMap.release(); @@ -7585,14 +7587,14 @@ void LLPipeline::generateSMAABuffers(LLRenderTarget* src) { if (!use_sample) { - src->bindTexture(0, channel, LLTexUnit::TFO_POINT); - gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + src->bindTexture(0, channel, LLTexUnit::TFO_BILINEAR); } else { gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mSMAASampleMap); - gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); } + gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); } //if (use_stencil) @@ -7986,7 +7988,7 @@ void LLPipeline::renderFinalize() static LLCachedControl has_hdr(gSavedSettings, "RenderHDREnabled", true); bool hdr = gGLManager.mGLVersion > 4.05f && has_hdr(); - + LLRenderTarget* postHDRBuffer = &mRT->screen; if (hdr) { copyScreenSpaceReflections(&mRT->screen, &mSceneMap); @@ -7995,22 +7997,31 @@ void LLPipeline::renderFinalize() generateExposure(&mLuminanceMap, &mExposureMap); - tonemap(&mRT->screen, &mPostMap); + tonemap(&mRT->screen, &mRT->deferredLight); - applyCAS(&mPostMap, &mRT->screen); + static LLCachedControl cas_sharpness(gSavedSettings, "RenderCASSharpness", 0.4f); + if (cas_sharpness != 0.0f && gCASProgram.isComplete()) + { + applyCAS(&mRT->deferredLight, &mRT->screen); + postHDRBuffer = &mRT->screen; + } + else + { + postHDRBuffer = &mRT->deferredLight; + } } - generateSMAABuffers(&mRT->screen); - - gammaCorrect(&mRT->screen, &mPostMap); + gammaCorrect(postHDRBuffer, &mPostPingMap); LLVertexBuffer::unbind(); - applySMAA(&mPostMap, &mRT->screen); + generateGlow(&mPostPingMap); - generateGlow(&mRT->screen); + LLRenderTarget* sourceBuffer = &mPostPingMap; + LLRenderTarget* targetBuffer = &mPostPongMap; - combineGlow(&mRT->screen, &mPostMap); + combineGlow(sourceBuffer, targetBuffer); + std::swap(sourceBuffer, targetBuffer); gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; @@ -8018,13 +8029,24 @@ void LLPipeline::renderFinalize() gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - renderDoF(&mPostMap, &mRT->screen); + if((RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) && + RenderDepthOfField && + !gCubeSnapshot) + { + renderDoF(sourceBuffer, targetBuffer); + std::swap(sourceBuffer, targetBuffer); + } - LLRenderTarget* finalBuffer = &mRT->screen; - if (RenderFSAAType == 1) + if (RenderFSAAType == 1) + { + applyFXAA(sourceBuffer, targetBuffer); + std::swap(sourceBuffer, targetBuffer); + } + else if (RenderFSAAType == 2) { - applyFXAA(&mRT->screen, &mPostMap); - finalBuffer = &mPostMap; + generateSMAABuffers(sourceBuffer); + applySMAA(sourceBuffer, targetBuffer); + std::swap(sourceBuffer, targetBuffer); } if (RenderBufferVisualization > -1) @@ -8035,16 +8057,16 @@ void LLPipeline::renderFinalize() case 1: case 2: case 3: - visualizeBuffers(&mRT->deferredScreen, finalBuffer, RenderBufferVisualization); + visualizeBuffers(&mRT->deferredScreen, sourceBuffer, RenderBufferVisualization); break; case 4: - visualizeBuffers(&mLuminanceMap, finalBuffer, 0); + visualizeBuffers(&mLuminanceMap, sourceBuffer, 0); break; case 5: { if (RenderFSAAType > 0) { - visualizeBuffers(&mFXAAMap, finalBuffer, 0); + visualizeBuffers(&mFXAAMap, sourceBuffer, 0); } break; } @@ -8052,7 +8074,7 @@ void LLPipeline::renderFinalize() { if (RenderFSAAType == 2) { - visualizeBuffers(&mSMAABlendBuffer, finalBuffer, 0); + visualizeBuffers(&mSMAABlendBuffer, sourceBuffer, 0); } break; } @@ -8066,10 +8088,10 @@ void LLPipeline::renderFinalize() gDeferredPostNoDoFNoiseProgram.bind(); // Add noise as part of final render to screen pass to avoid damaging other post effects // Whatever is last in the above post processing chain should _always_ be rendered directly here. If not, expect problems. - gDeferredPostNoDoFNoiseProgram.bindTexture(LLShaderMgr::DEFERRED_DIFFUSE, finalBuffer); + gDeferredPostNoDoFNoiseProgram.bindTexture(LLShaderMgr::DEFERRED_DIFFUSE, sourceBuffer); gDeferredPostNoDoFNoiseProgram.bindTexture(LLShaderMgr::DEFERRED_DEPTH, &mRT->deferredScreen, true); - gDeferredPostNoDoFNoiseProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, (GLfloat)finalBuffer->getWidth(), (GLfloat)finalBuffer->getHeight()); + gDeferredPostNoDoFNoiseProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, (GLfloat)sourceBuffer->getWidth(), (GLfloat)sourceBuffer->getHeight()); { LLGLDepthTest depth_test(GL_TRUE, GL_TRUE, GL_ALWAYS); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 315e38ed8c7..b3796a6febc 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -730,7 +730,8 @@ class LLPipeline LLRenderTarget mLastExposure; // tonemapped and gamma corrected render ready for post - LLRenderTarget mPostMap; + LLRenderTarget mPostPingMap; + LLRenderTarget mPostPongMap; // FXAA helper target LLRenderTarget mFXAAMap; From 3f65a4bfec71a9950a541f9e6195a572a0622b48 Mon Sep 17 00:00:00 2001 From: Rye Date: Fri, 22 Aug 2025 13:13:03 -0400 Subject: [PATCH 093/145] Fix test build on macOS --- indra/integration_tests/llimage_libtest/CMakeLists.txt | 2 -- indra/llcorehttp/tests/test_httprequest.hpp | 6 +++--- indra/llfilesystem/tests/lldir_test.cpp | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt index 84d1feb7588..e6ff142626c 100644 --- a/indra/integration_tests/llimage_libtest/CMakeLists.txt +++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt @@ -33,8 +33,6 @@ target_link_libraries(llimage_libtest llfilesystem llmath llimage - llkdu - llimagej2coj ) # Ensure people working on the viewer don't break this library diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp index 1afc08a108c..77ed8df066a 100644 --- a/indra/llcorehttp/tests/test_httprequest.hpp +++ b/indra/llcorehttp/tests/test_httprequest.hpp @@ -2786,7 +2786,7 @@ void HttpRequestTestObjectType::test<22>() for (int i(0); i < test_count; ++i) { char buffer[128]; - sprintf(buffer, "/bug2295/%d/", i); + snprintf(buffer, sizeof(buffer), "/bug2295/%d/", i); HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, url_base + buffer, 0, @@ -2817,7 +2817,7 @@ void HttpRequestTestObjectType::test<22>() for (int i(0); i < test2_count; ++i) { char buffer[128]; - sprintf(buffer, "/bug2295/00000012/%d/", i); + snprintf(buffer, sizeof(buffer), "/bug2295/00000012/%d/", i); HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, url_base + buffer, 0, @@ -2848,7 +2848,7 @@ void HttpRequestTestObjectType::test<22>() for (int i(0); i < test3_count; ++i) { char buffer[128]; - sprintf(buffer, "/bug2295/inv_cont_range/%d/", i); + snprintf(buffer, sizeof(buffer), "/bug2295/inv_cont_range/%d/", i); HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID, url_base + buffer, 0, diff --git a/indra/llfilesystem/tests/lldir_test.cpp b/indra/llfilesystem/tests/lldir_test.cpp index 6e191ad096d..d7d57fa86fb 100644 --- a/indra/llfilesystem/tests/lldir_test.cpp +++ b/indra/llfilesystem/tests/lldir_test.cpp @@ -435,7 +435,7 @@ namespace tut for (counter=0, foundUnused=false; !foundUnused; counter++ ) { char counterStr[3]; - sprintf(counterStr, "%02d", counter); + snprintf(counterStr, sizeof(counterStr), "%02d", counter); uniqueDir = dirbase + counterStr; foundUnused = ! ( LLFile::isdir(uniqueDir) || LLFile::isfile(uniqueDir) ); } From 1022be69862db187594f2971fa9602d46f13e372 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 21 Aug 2025 21:55:25 +0300 Subject: [PATCH 094/145] #4570 Sanity check bandwidth input Going above this will just make server throttle things and viewer's own throttlig won't be effective when viewer can't keep up. --- indra/newview/lltexturefetch.cpp | 6 +++--- indra/newview/lltextureview.cpp | 3 ++- indra/newview/llviewerthrottle.cpp | 11 ++++++++++- indra/newview/llviewerthrottle.h | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index cc187a1f989..93b5806acf4 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -49,6 +49,7 @@ #include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerstatsrecorder.h" +#include "llviewerthrottle.h" #include "llviewerassetstats.h" #include "llworld.h" #include "llsdparam.h" @@ -2434,7 +2435,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, bool threaded, bool qa_mod mOriginFetchSource(LLTextureFetch::FROM_ALL), mTextureInfoMainThread(false) { - mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS"); + mMaxBandwidth = LLViewerThrottle::getMaxBandwidthKbps(); mTextureInfo.setLogging(true); LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); @@ -2953,11 +2954,10 @@ void LLTextureFetch::commonUpdate() size_t LLTextureFetch::update(F32 max_time_ms) { LL_PROFILE_ZONE_SCOPED; - static LLCachedControl band_width(gSavedSettings,"ThrottleBandwidthKBPS", 3000.0); { mNetworkQueueMutex.lock(); // +Mfnq - mMaxBandwidth = band_width(); + mMaxBandwidth = LLViewerThrottle::getMaxBandwidthKbps(); add(LLStatViewer::TEXTURE_NETWORK_DATA_RECEIVED, mHTTPTextureBits); mHTTPTextureBits = (U32Bits)0; diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 8560a01c4b0..8cbede83031 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -49,6 +49,7 @@ #include "llviewerobjectlist.h" #include "llviewertexture.h" #include "llviewertexturelist.h" +#include "llviewerthrottle.h" #include "llviewerwindow.h" #include "llwindow.h" #include "llvovolume.h" @@ -633,7 +634,7 @@ void LLGLTexMemBar::draw() LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, &x_right); F32Kilobits bandwidth(LLAppViewer::getTextureFetch()->getTextureBandwidth()); - F32Kilobits max_bandwidth(gSavedSettings.getF32("ThrottleBandwidthKBPS")); + F32Kilobits max_bandwidth(LLViewerThrottle::getMaxBandwidthKbps()); color = bandwidth > max_bandwidth ? LLColor4::red : bandwidth > max_bandwidth*.75f ? LLColor4::yellow : text_color; color[VALPHA] = text_color[VALPHA]; text = llformat("BW:%.0f/%.0f",bandwidth.value(), max_bandwidth.value()); diff --git a/indra/newview/llviewerthrottle.cpp b/indra/newview/llviewerthrottle.cpp index 8d935e42434..3ccfbea6e23 100644 --- a/indra/newview/llviewerthrottle.cpp +++ b/indra/newview/llviewerthrottle.cpp @@ -225,7 +225,7 @@ void LLViewerThrottle::setMaxBandwidth(F32 kbits_per_second, bool from_event) void LLViewerThrottle::load() { - mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS")*1024; + mMaxBandwidth = getMaxBandwidthKbps() * 1024; resetDynamicThrottle(); mCurrent.dump(); } @@ -242,6 +242,15 @@ void LLViewerThrottle::sendToSim() const mCurrent.sendToSim(); } +F32 LLViewerThrottle::getMaxBandwidthKbps() +{ + constexpr F32 MIN_BANDWIDTH = 100.0f; // 100 Kbps + constexpr F32 MAX_BANDWIDTH = 10000.0f; // 10 Mbps + + static LLCachedControl bandwidth(gSavedSettings, "ThrottleBandwidthKBPS", 3000.0); + return llclamp(bandwidth(), MIN_BANDWIDTH, MAX_BANDWIDTH); +} + LLViewerThrottleGroup LLViewerThrottle::getThrottleGroup(const F32 bandwidth_kbps) { diff --git a/indra/newview/llviewerthrottle.h b/indra/newview/llviewerthrottle.h index 9973c885499..ef898a97d75 100644 --- a/indra/newview/llviewerthrottle.h +++ b/indra/newview/llviewerthrottle.h @@ -64,6 +64,7 @@ class LLViewerThrottle void save() const; void sendToSim() const; + static F32 getMaxBandwidthKbps(); F32 getMaxBandwidth()const { return mMaxBandwidth; } F32 getCurrentBandwidth() const { return mCurrentBandwidth; } From cefee59b0e5fff683a50fe61633a9c14493d7145 Mon Sep 17 00:00:00 2001 From: Callum Linden <113564339+callumlinden@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:21:31 -0700 Subject: [PATCH 095/145] Improved open performance for some web based UI floaters by preloading the web content during login (#4574) * First phase of some work to replace certain UI web based floaters with a much more simple floater (no more browserish web-content-floater) and then pre-load content as login is progressing. This means that after login, the floater can be opened much more rapidly than now. This first commit does this process for the Search floater * This commit brings in a new marketplace floater than hosts the marketplace web page (no more webcontent floater here either). It works as expected and opens quickly but the user is not logged in when the page is opened so that needs to be tackled before we can declare that this is a viable solution * This commit introduces a way to set the openID cookie that arrives via login.cgi into all the instances that are preloaded - the result is that when you open the preloaded floater after login, you are logged into your linden account * Fix a mac only warning as error - function overrides a member function but is not marked 'override' * Marchcat spotted left over cruft from earlier dev when we used a trimmed down URL for the pre-load search. Now we use the same search URL throughout and zero out the query parameters --- indra/newview/CMakeLists.txt | 2 + indra/newview/llfloatermarketplace.cpp | 47 +++++ indra/newview/llfloatermarketplace.h | 40 ++++ indra/newview/llfloatersearch.cpp | 183 +++++++----------- indra/newview/llfloatersearch.h | 82 ++------ indra/newview/llstatusbar.cpp | 8 +- indra/newview/llstatusbar.h | 1 + indra/newview/llviewerfloaterreg.cpp | 3 + indra/newview/llviewermedia.cpp | 65 ++++--- indra/newview/llviewermenu.cpp | 7 - indra/newview/llviewerwindow.cpp | 12 ++ .../skins/default/xui/da/floater_search.xml | 16 -- .../skins/default/xui/de/floater_search.xml | 16 -- .../default/xui/en/floater_marketplace.xml | 26 +++ .../skins/default/xui/en/floater_search.xml | 40 ++-- .../skins/default/xui/es/floater_search.xml | 16 -- .../skins/default/xui/fr/floater_search.xml | 16 -- .../skins/default/xui/it/floater_search.xml | 16 -- .../skins/default/xui/ja/floater_search.xml | 16 -- .../skins/default/xui/pt/floater_search.xml | 16 -- .../skins/default/xui/ru/floater_search.xml | 16 -- .../skins/default/xui/tr/floater_search.xml | 16 -- .../skins/default/xui/zh/floater_search.xml | 16 -- 23 files changed, 289 insertions(+), 387 deletions(-) create mode 100644 indra/newview/llfloatermarketplace.cpp create mode 100644 indra/newview/llfloatermarketplace.h delete mode 100644 indra/newview/skins/default/xui/da/floater_search.xml delete mode 100644 indra/newview/skins/default/xui/de/floater_search.xml create mode 100644 indra/newview/skins/default/xui/en/floater_marketplace.xml delete mode 100644 indra/newview/skins/default/xui/es/floater_search.xml delete mode 100644 indra/newview/skins/default/xui/fr/floater_search.xml delete mode 100644 indra/newview/skins/default/xui/it/floater_search.xml delete mode 100644 indra/newview/skins/default/xui/ja/floater_search.xml delete mode 100644 indra/newview/skins/default/xui/pt/floater_search.xml delete mode 100644 indra/newview/skins/default/xui/ru/floater_search.xml delete mode 100644 indra/newview/skins/default/xui/tr/floater_search.xml delete mode 100644 indra/newview/skins/default/xui/zh/floater_search.xml diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 62af812971d..f2aec208a1e 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -393,6 +393,7 @@ set(viewer_SOURCE_FILES llmaniprotate.cpp llmanipscale.cpp llmaniptranslate.cpp + llfloatermarketplace.cpp llmarketplacefunctions.cpp llmarketplacenotifications.cpp llmaterialeditor.cpp @@ -930,6 +931,7 @@ set(viewer_HEADER_FILES llfloaterlinkreplace.h llfloaterloadprefpreset.h llfloatermap.h + llfloatermarketplace.h llfloatermarketplacelistings.h llfloatermediasettings.h llfloatermemleak.h diff --git a/indra/newview/llfloatermarketplace.cpp b/indra/newview/llfloatermarketplace.cpp new file mode 100644 index 00000000000..889daf84ab3 --- /dev/null +++ b/indra/newview/llfloatermarketplace.cpp @@ -0,0 +1,47 @@ +/** + * @file llfloatermarketplace.cpp + * @brief floater for the Marketplace web site + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloatermarketplace.h" +#include "lluictrlfactory.h" + +LLFloaterMarketplace::LLFloaterMarketplace(const LLSD& key) + : LLFloater(key) +{ +} + +LLFloaterMarketplace::~LLFloaterMarketplace() +{ +} + +bool LLFloaterMarketplace::postBuild() +{ + enableResizeCtrls(true, true, false); + return true; +} + + diff --git a/indra/newview/llfloatermarketplace.h b/indra/newview/llfloatermarketplace.h new file mode 100644 index 00000000000..2ae4d0d64a2 --- /dev/null +++ b/indra/newview/llfloatermarketplace.h @@ -0,0 +1,40 @@ +/** + * @file llfloatermarketplace.h + * @brief floater for the Marketplace web site + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#pragma once + +#include "llfloater.h" + +class LLFloaterMarketplace: + public LLFloater +{ + friend class LLFloaterReg; +private: + LLFloaterMarketplace(const LLSD& key); + ~LLFloaterMarketplace(); + bool postBuild() override; +}; + diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index d3c8bf34513..9762154a269 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -1,11 +1,10 @@ /** * @file llfloatersearch.cpp - * @author Martin Reddy - * @brief Search floater - uses an embedded web browser control + * @brief Floater for Search (update 2025, preload) * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2011, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,68 +26,34 @@ #include "llviewerprecompiledheaders.h" +#include "llfloatersearch.h" + +#include "llagent.h" #include "llcommandhandler.h" #include "llfloaterreg.h" -#include "llfloatersearch.h" -#include "llhttpconstants.h" #include "llmediactrl.h" -#include "llnotificationsutil.h" -#include "lllogininstance.h" -#include "lluri.h" -#include "llagent.h" -#include "llui.h" +#include "lluictrlfactory.h" #include "llviewercontrol.h" #include "llweb.h" // support secondlife:///app/search/{CATEGORY}/{QUERY} SLapps -class LLSearchHandler : public LLCommandHandler -{ -public: - // requires trusted browser to trigger - LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_CLICK_ONLY) { } - bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) - { - const size_t parts = tokens.size(); - - // get the (optional) category for the search - std::string collection; - if (parts > 0) - { - collection = tokens[0].asString(); +class LLSearchHandler : public LLCommandHandler { + public: + // requires trusted browser to trigger + LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_CLICK_ONLY) { } + bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { + const size_t parts = tokens.size(); + + // open the search floater and perform the requested search + LLFloaterReg::showInstance("search", tokens); + return true; } - - // get the (optional) search string - std::string search_text; - if (parts > 1) - { - search_text = tokens[1].asString(); - } - - // create the LLSD arguments for the search floater - LLFloaterSearch::Params p; - p.search.collection = collection; - p.search.query = LLURI::unescape(search_text); - - // open the search floater and perform the requested search - LLFloaterReg::showInstance("search", p); - return true; - } }; LLSearchHandler gSearchHandler; -LLFloaterSearch::SearchQuery::SearchQuery() -: category("category", ""), - collection("collection", ""), - query("query") -{} - -LLFloaterSearch::LLFloaterSearch(const Params& key) : - LLFloaterWebContent(key), - mSearchGodLevel(0) +LLFloaterSearch::LLFloaterSearch(const LLSD& key) + : LLFloater(key) { - // declare a map that transforms a category name into - // the URL suffix that is used to search that category - mSearchType.insert("standard"); mSearchType.insert("land"); mSearchType.insert("classified"); @@ -100,76 +65,61 @@ LLFloaterSearch::LLFloaterSearch(const Params& key) : mCollectionType.insert("people"); } -bool LLFloaterSearch::postBuild() +LLFloaterSearch::~LLFloaterSearch() { - LLFloaterWebContent::postBuild(); - mWebBrowser->addObserver(this); - - return true; } -void LLFloaterSearch::onOpen(const LLSD& key) +void LLFloaterSearch::onOpen(const LLSD& tokens) { - Params p(key); - p.trusted_content = true; - p.allow_address_entry = false; - - LLFloaterWebContent::onOpen(p); - mWebBrowser->setFocus(true); - search(p.search); + initiateSearch(tokens); } -void LLFloaterSearch::onClose(bool app_quitting) +void LLFloaterSearch::initiateSearch(const LLSD& tokens) { - LLFloaterWebContent::onClose(app_quitting); - // tear down the web view so we don't show the previous search - // result when the floater is opened next time - destroy(); -} + std::string url = gSavedSettings.getString("SearchURL"); -void LLFloaterSearch::godLevelChanged(U8 godlevel) -{ - // search results can change based upon god level - if the user - // changes god level, then give them a warning (we don't refresh - // the search as this might undo any page navigation or - // AJAX-driven changes since the last search). + LLSD subs; - //FIXME: set status bar text + // Setting this substitution here results in a full set of collections being + // substituted into the final URL using the logic from the original search. + subs["TYPE"] = "standard"; - //getChildView("refresh_search")->setVisible( (godlevel != mSearchGodLevel)); -} + const size_t parts = tokens.size(); -void LLFloaterSearch::search(const SearchQuery &p) -{ - if (! mWebBrowser || !p.validateBlock()) + // get the (optional) category for the search + std::string collection; + if (parts > 0) { - return; + collection = tokens[0].asString(); } - // reset the god level warning as we're sending the latest state - getChildView("refresh_search")->setVisible(false); - mSearchGodLevel = gAgent.getGodLevel(); + // get the (optional) search string + std::string search_text; + if (parts > 1) + { + search_text = tokens[1].asString(); + } - // work out the subdir to use based on the requested category - LLSD subs; - if (mSearchType.find(p.category) != mSearchType.end()) + // TODO: where does category get set? I cannot find a reference to + // it in internal docs - might be conflated with values in mSearchType + std::string category; + if (mSearchType.find(category) != mSearchType.end()) { - subs["TYPE"] = p.category; + subs["TYPE"] = category; } else { subs["TYPE"] = "standard"; } - // add the search query string - subs["QUERY"] = LLURI::escape(p.query); + subs["QUERY"] = LLURI::escape(search_text); subs["COLLECTION"] = ""; if (subs["TYPE"] == "standard") { - if (mCollectionType.find(p.collection) != mCollectionType.end()) + if (mCollectionType.find(collection) != mCollectionType.end()) { - subs["COLLECTION"] = "&collection_chosen=" + std::string(p.collection); + subs["COLLECTION"] = "&collection_chosen=" + std::string(collection); } else { @@ -182,30 +132,41 @@ void LLFloaterSearch::search(const SearchQuery &p) } } - // add the user's preferred maturity (can be changed via prefs) - std::string maturity; + // Default to PG + std::string maturity = "g"; if (gAgent.prefersAdult()) { - maturity = "gma"; // PG,Mature,Adult + // PG,Mature,Adult + maturity = "gma"; } else if (gAgent.prefersMature()) { - maturity = "gm"; // PG,Mature - } - else - { - maturity = "g"; // PG + // PG,Mature + maturity = "gm"; } subs["MATURITY"] = maturity; - // add the user's god status + // God status subs["GODLIKE"] = gAgent.isGodlike() ? "1" : "0"; - // get the search URL and expand all of the substitutions - // (also adds things like [LANGUAGE], [VERSION], [OS], etc.) - std::string url = gSavedSettings.getString("SearchURL"); + // This call expands a set of generic substitutions like language, viewer version + // etc. and then also does the same with the list of subs passed in. url = LLWeb::expandURLSubstitutions(url, subs); - // and load the URL in the web view - mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML); + // Naviation to the calculated URL - we know it's HTML so we can + // tell the media system not to bother with the MIME type check. + LLMediaCtrl* search_browser = findChild("search_contents"); + search_browser->navigateTo(url, HTTP_CONTENT_TEXT_HTML); +} + +bool LLFloaterSearch::postBuild() +{ + enableResizeCtrls(true, true, false); + + // This call is actioned by the preload code in llViewerWindow + // that creates the search floater during the login process + // using a generic search with no query + initiateSearch(LLSD()); + + return true; } diff --git a/indra/newview/llfloatersearch.h b/indra/newview/llfloatersearch.h index beaac2ad2f1..e8a2be4797c 100644 --- a/indra/newview/llfloatersearch.h +++ b/indra/newview/llfloatersearch.h @@ -1,11 +1,10 @@ /** * @file llfloatersearch.h - * @author Martin Reddy - * @brief Search floater - uses an embedded web browser control + * @brief Floater for Search (update 2025, preload) * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2011, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,70 +24,23 @@ * $/LicenseInfo$ */ -#ifndef LL_LLFLOATERSEARCH_H -#define LL_LLFLOATERSEARCH_H +#pragma once -#include "llfloaterwebcontent.h" -#include "llviewermediaobserver.h" +#include "llfloater.h" -#include +class LLFloaterSearch: + public LLFloater { + friend class LLFloaterReg; -class LLMediaCtrl; + public: + void onOpen(const LLSD& key) override; -/// -/// The search floater allows users to perform all search operations. -/// All search functionality is now implemented via web services and -/// so this floater simply embeds a web view and displays the search -/// web page. The browser control is explicitly marked as "trusted" -/// so that the user can click on teleport links in search results. -/// -class LLFloaterSearch : - public LLFloaterWebContent -{ -public: - struct SearchQuery : public LLInitParam::Block - { - Optional category; - Optional collection; - Optional query; + private: + LLFloaterSearch(const LLSD& key); + ~LLFloaterSearch(); + void initiateSearch(const LLSD& tokens); + bool postBuild() override; - SearchQuery(); - }; - - struct _Params : public LLInitParam::Block<_Params, LLFloaterWebContent::Params> - { - Optional search; - }; - - typedef LLSDParamAdapter<_Params> Params; - - LLFloaterSearch(const Params& key); - - /// show the search floater with a new search - /// see search() for details on the key parameter. - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ void onClose(bool app_quitting); - - /// perform a search with the specific search term. - /// The key should be a map that can contain the following keys: - /// - "id": specifies the text phrase to search for - /// - "category": one of "all" (default), "people", "places", - /// "events", "groups", "wiki", "destinations", "classifieds" - void search(const SearchQuery &query); - - /// changing godmode can affect the search results that are - /// returned by the search website - use this method to tell the - /// search floater that the user has changed god level. - void godLevelChanged(U8 godlevel); - -private: - /*virtual*/ bool postBuild(); - - std::set mSearchType; - std::set mCollectionType; - U8 mSearchGodLevel; + std::set mSearchType; + std::set mCollectionType; }; - -#endif // LL_LLFLOATERSEARCH_H - diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index bb93e2e79e9..82c959d7f77 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -161,7 +161,8 @@ bool LLStatusBar::postBuild() getChild("buyL")->setCommitCallback( boost::bind(&LLStatusBar::onClickBuyCurrency, this)); - getChild("goShop")->setCommitCallback(boost::bind(&LLWeb::loadURL, gSavedSettings.getString("MarketplaceURL"), LLStringUtil::null, LLStringUtil::null)); + getChild("goShop")->setCommitCallback( + boost::bind(&LLStatusBar::onClickShop, this)); mBoxBalance = getChild("balance"); mBoxBalance->setClickedCallback(&LLStatusBar::onClickRefreshBalance, this); @@ -520,6 +521,11 @@ void LLStatusBar::onClickBuyCurrency() LLFirstUse::receiveLindens(false); } +void LLStatusBar::onClickShop() +{ + LLFloaterReg::toggleInstanceOrBringToFront("marketplace"); +} + void LLStatusBar::onMouseEnterPresetsCamera() { LLView* popup_holder = gViewerWindow->getRootView()->getChildView("popup_holder"); diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index a8fc621ff83..eb4ca8e8945 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -101,6 +101,7 @@ class LLStatusBar private: void onClickBuyCurrency(); + void onClickShop(); void onVolumeChanged(const LLSD& newvalue); void onVoiceChanged(const LLSD& newvalue); void onObscureBalanceChanged(const LLSD& newvalue); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 4b3af6d7e88..3b35ca8db1b 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -21,6 +21,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -98,6 +99,7 @@ #include "llfloaterlinkreplace.h" #include "llfloaterloadprefpreset.h" #include "llfloatermap.h" +#include "llfloatermarketplace.h" #include "llfloatermarketplacelistings.h" #include "llfloatermediasettings.h" #include "llfloatermemleak.h" @@ -419,6 +421,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("marketplace", "floater_marketplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("marketplace_listings", "floater_marketplace_listings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("marketplace_validation", "floater_marketplace_validation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 82a52e63f67..c6bc252efd2 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1259,35 +1259,46 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) { LLAppViewer::instance()->postToMainCoro([=]() { - LLMediaCtrl* media_instance = LLFloaterReg::getInstance("destinations")->getChild("destination_guide_contents"); - if (media_instance) + std::string cookie_host = authority.substr(hostStart, hostEnd - hostStart); + std::string cookie_name = ""; + std::string cookie_value = ""; + std::string cookie_path = ""; + bool httponly = true; + bool secure = true; + + LLViewerMedia* inst = getInstance(); + if (inst->parseRawCookie(inst->mOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure)) { - LLViewerMedia* inst = getInstance(); - std::string cookie_host = authority.substr(hostStart, hostEnd - hostStart); - std::string cookie_name = ""; - std::string cookie_value = ""; - std::string cookie_path = ""; - bool httponly = true; - bool secure = true; - if (inst->parseRawCookie(inst->mOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure) && - media_instance->getMediaPlugin()) + // MAINT-5711 - inexplicably, the CEF setCookie function will no longer set the cookie if the + // url and domain are not the same. This used to be my.sl.com and id.sl.com respectively and worked. + // For now, we use the URL for the OpenID POST request since it will have the same authority + // as the domain field. + // (Feels like there must be a less dirty way to construct a URL from component LLURL parts) + // MAINT-6392 - Rider: Do not change, however, the original URI requested, since it is used further + // down. + std::string cefUrl(std::string(inst->mOpenIDURL.mURI) + "://" + std::string(inst->mOpenIDURL.mAuthority)); + + // list of floater names and webbrowser therein to set the cookie that arrived via login into + struct MediaCookieInstance { + std::string floater_name; + std::string browser_name; + }; + struct MediaCookieInstance media_cookie_instances[] = { + {"search", "search_contents" }, + {"marketplace", "marketplace_contents" }, + {"destinations", "destination_guide_contents" }, + }; + for (MediaCookieInstance mci : media_cookie_instances) { - // MAINT-5711 - inexplicably, the CEF setCookie function will no longer set the cookie if the - // url and domain are not the same. This used to be my.sl.com and id.sl.com respectively and worked. - // For now, we use the URL for the OpenID POST request since it will have the same authority - // as the domain field. - // (Feels like there must be a less dirty way to construct a URL from component LLURL parts) - // MAINT-6392 - Rider: Do not change, however, the original URI requested, since it is used further - // down. - std::string cefUrl(std::string(inst->mOpenIDURL.mURI) + "://" + std::string(inst->mOpenIDURL.mAuthority)); - - media_instance->getMediaPlugin()->setCookie(cefUrl, cookie_name, cookie_value, cookie_host, - cookie_path, httponly, secure); - - // Now that we have parsed the raw cookie, we must store it so that each new media instance - // can also get a copy and faciliate logging into internal SL sites. - media_instance->getMediaPlugin()->storeOpenIDCookie(cefUrl, cookie_name, cookie_value, - cookie_host, cookie_path, httponly, secure); + LLMediaCtrl* media_instance = LLFloaterReg::getInstance(mci.floater_name)->getChild(mci.browser_name); + if (media_instance && media_instance->getMediaPlugin()) + { + media_instance->getMediaPlugin()->setCookie(cefUrl, cookie_name, cookie_value, cookie_host, + cookie_path, httponly, secure); + + media_instance->getMediaPlugin()->storeOpenIDCookie(cefUrl, cookie_name, cookie_value, + cookie_host, cookie_path, httponly, secure); + } } } }); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 7a8a57c03df..f7688b762fb 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -4354,13 +4354,6 @@ void set_god_level(U8 god_level) // changing god-level can affect which menus we see show_debug_menus(); - - // changing god-level can invalidate search results - LLFloaterSearch *search = dynamic_cast(LLFloaterReg::getInstance("search")); - if (search) - { - search->godLevelChanged(god_level); - } } #ifdef TOGGLE_HACKED_GODLIKE_VIEWER diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index b0408b73ada..0edb7c70ea5 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2309,6 +2309,18 @@ void LLViewerWindow::initWorldUI() url = LLWeb::expandURLSubstitutions(url, LLSD()); avatar_welcome_pack->navigateTo(url, HTTP_CONTENT_TEXT_HTML); } + LLMediaCtrl* search = LLFloaterReg::getInstance("search")->findChild("search_contents"); + if (search) + { + search->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); + } + LLMediaCtrl* marketplace = LLFloaterReg::getInstance("marketplace")->getChild("marketplace_contents"); + if (marketplace) + { + marketplace->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); + std::string url = gSavedSettings.getString("MarketplaceURL"); + marketplace->navigateTo(url, HTTP_CONTENT_TEXT_HTML); + } } } diff --git a/indra/newview/skins/default/xui/da/floater_search.xml b/indra/newview/skins/default/xui/da/floater_search.xml deleted file mode 100644 index 80a30b1aa17..00000000000 --- a/indra/newview/skins/default/xui/da/floater_search.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Henter... - - - Færdig - - - - - Gentag søgning med "God level" - - - - diff --git a/indra/newview/skins/default/xui/de/floater_search.xml b/indra/newview/skins/default/xui/de/floater_search.xml deleted file mode 100644 index bd39bf2bceb..00000000000 --- a/indra/newview/skins/default/xui/de/floater_search.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Wird geladen... - - - Fertig - - - - - Suche wiederholen, um aktuellen Gott-Level zu berücksichtigen - - - - diff --git a/indra/newview/skins/default/xui/en/floater_marketplace.xml b/indra/newview/skins/default/xui/en/floater_marketplace.xml new file mode 100644 index 00000000000..2299e02c63e --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_marketplace.xml @@ -0,0 +1,26 @@ + + + + diff --git a/indra/newview/skins/default/xui/en/floater_search.xml b/indra/newview/skins/default/xui/en/floater_search.xml index fc1e32915a8..76a486e211f 100644 --- a/indra/newview/skins/default/xui/en/floater_search.xml +++ b/indra/newview/skins/default/xui/en/floater_search.xml @@ -1,18 +1,26 @@ + positioning="cascading" + legacy_header_height="225" + can_minimize="true" + can_close="true" + can_resize="true" + min_height="800" + min_width="800" + height="800" + layout="topleft" + name="Search" + single_instance="true" + help_topic="search" + save_rect="true" + save_visibility="true" + title="SEARCH" + width="800"> + + diff --git a/indra/newview/skins/default/xui/es/floater_search.xml b/indra/newview/skins/default/xui/es/floater_search.xml deleted file mode 100644 index e24d8064a14..00000000000 --- a/indra/newview/skins/default/xui/es/floater_search.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Cargando... - - - Hecho - - - - - Redo search to reflect current God level - - - - diff --git a/indra/newview/skins/default/xui/fr/floater_search.xml b/indra/newview/skins/default/xui/fr/floater_search.xml deleted file mode 100644 index 32800182ea8..00000000000 --- a/indra/newview/skins/default/xui/fr/floater_search.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Chargement... - - - Terminé - - - - - Relancer la recherche pour refléter le niveau divin actuel - - - - diff --git a/indra/newview/skins/default/xui/it/floater_search.xml b/indra/newview/skins/default/xui/it/floater_search.xml deleted file mode 100644 index ac3dc17aa3f..00000000000 --- a/indra/newview/skins/default/xui/it/floater_search.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Caricamento in corso... - - - Fine - - - - - Ripeti ricerca in modo che rifletta il livello di diritti Admin attuale - - - - diff --git a/indra/newview/skins/default/xui/ja/floater_search.xml b/indra/newview/skins/default/xui/ja/floater_search.xml deleted file mode 100644 index 531ac77f95f..00000000000 --- a/indra/newview/skins/default/xui/ja/floater_search.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - 読み込んでいます…。 - - - 完了 - - - - - 現在のゴッドレベルに反映させるため、検索をやり直してください。 - - - - diff --git a/indra/newview/skins/default/xui/pt/floater_search.xml b/indra/newview/skins/default/xui/pt/floater_search.xml deleted file mode 100644 index 3509cb786d1..00000000000 --- a/indra/newview/skins/default/xui/pt/floater_search.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Carregando... - - - Pronto - - - - - Buscar novamente com status God - - - - diff --git a/indra/newview/skins/default/xui/ru/floater_search.xml b/indra/newview/skins/default/xui/ru/floater_search.xml deleted file mode 100644 index 405a6598ac6..00000000000 --- a/indra/newview/skins/default/xui/ru/floater_search.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Загрузка... - - - Готово - - - - - Повторить поиск, чтобы показать текущий уровень творца - - - - diff --git a/indra/newview/skins/default/xui/tr/floater_search.xml b/indra/newview/skins/default/xui/tr/floater_search.xml deleted file mode 100644 index 08c1e5162c7..00000000000 --- a/indra/newview/skins/default/xui/tr/floater_search.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - Yükleniyor... - - - Tamamlandı - - - - - Mevcut Yönetici seviyesini dikkate alarak aramayı yenile - - - - diff --git a/indra/newview/skins/default/xui/zh/floater_search.xml b/indra/newview/skins/default/xui/zh/floater_search.xml deleted file mode 100644 index 3e85a529ae3..00000000000 --- a/indra/newview/skins/default/xui/zh/floater_search.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - 載入中... - - - 完成 - - - - - 以目前具備的神階級再搜尋一次 - - - - From bebd1b208e1b342fabf59844851124a91513e83b Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Fri, 22 Aug 2025 17:10:29 -0700 Subject: [PATCH 096/145] Bring in Dullahan 1.20.0 and by that, CEF 139.0.28. Update the CEF media plugin accordingly to take account of Dullahan cache changes --- autobuild.xml | 10 +++++----- indra/media_plugins/cef/media_plugin_cef.cpp | 16 +--------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 5dcc9a980a9..2f2ab550122 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -448,11 +448,11 @@ archive hash - 8f3672e548c140a48296669b65cb4ce9a54154e2 + 67f6df74e64ec7706b59192dbdef1d0da2754127 hash_algorithm sha1 url - https://github.com/secondlife/dullahan/releases/download/v1.16.0-CEF_139.0.17/dullahan-1.16.0.202508120105_139.0.17_g6c347eb_chromium-139.0.7258.31-darwin64-16896111303.tar.zst + https://github.com/secondlife/dullahan/releases/download/v1.20.0-CEF_139.0.28a/dullahan-1.20.0.202508222243_139.0.28_g55ab8a8_chromium-139.0.7258.139-darwin64-17167490569.tar.zst name darwin64 @@ -476,11 +476,11 @@ archive hash - ec077eb13edf0b69324d73b49bb434e69e67d2d0 + 7fe15918eeeb5121b6c5af9427f581a775b88758 hash_algorithm sha1 url - https://github.com/secondlife/dullahan/releases/download/v1.16.0-CEF_139.0.17/dullahan-1.16.0.202508120105_139.0.17_g6c347eb_chromium-139.0.7258.31-windows64-16896111303.tar.zst + https://github.com/secondlife/dullahan/releases/download/v1.20.0-CEF_139.0.28a/dullahan-1.20.0.202508222244_139.0.28_g55ab8a8_chromium-139.0.7258.139-windows64-17167490569.tar.zst name windows64 @@ -493,7 +493,7 @@ copyright Copyright (c) 2017, Linden Research, Inc. version - 1.16.0.202508120105_139.0.17_g6c347eb_chromium-139.0.7258.31 + 1.20.0.202508222243_139.0.28_g55ab8a8_chromium-139.0.7258.139 name dullahan description diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 3f45ac971a8..52df4a96859 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -110,8 +110,6 @@ class MediaPluginCEF : bool mCanCopy; bool mCanPaste; std::string mRootCachePath; - std::string mCachePath; - std::string mContextCachePath; std::string mCefLogFile; bool mCefLogVerbose; std::vector mPickedFiles; @@ -149,7 +147,6 @@ MediaPluginBase(host_send_func, host_user_data) mCanCut = false; mCanCopy = false; mCanPaste = false; - mCachePath = ""; mCefLogFile = ""; mCefLogVerbose = false; mPickedFiles.clear(); @@ -649,10 +646,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string) // and set it to white settings.background_color = 0xffffffff; // white - settings.cache_enabled = true; settings.root_cache_path = mRootCachePath; - settings.cache_path = mCachePath; - settings.context_cache_path = mContextCachePath; settings.cookies_enabled = mCookiesEnabled; // configure proxy argument if enabled and valid @@ -768,15 +762,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string) mRootCachePath += std::to_string(getpid()); # endif - if (!subfolder.empty()) - { - mCachePath = mRootCachePath + path_separator + subfolder; - } - else - { - mCachePath = mRootCachePath; - } - mContextCachePath = ""; // disabled by "" + mCefLogFile = message_in.getValue("cef_log_file"); mCefLogVerbose = message_in.getValueBoolean("cef_verbose_log"); } From 8a585912adab1948e250c30d8ceb3588b9148600 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 26 Aug 2025 18:18:07 +0300 Subject: [PATCH 097/145] #4598 Crash in LLReflectionMapManager::update Not enough data for a solid conclusion (does something create settings in a thread?), but should be avoidable if we cache settings differently. --- indra/newview/llreflectionmapmanager.cpp | 41 +++++++++++++----------- indra/newview/llreflectionmapmanager.h | 8 +++++ indra/newview/llviewercontrol.cpp | 8 +++++ 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index 3391b7adf78..f24bb892dc1 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -145,6 +145,7 @@ static void touch_default_probe(LLReflectionMap* probe) LLReflectionMapManager::LLReflectionMapManager() { mDynamicProbeCount = LL_MAX_REFLECTION_PROBE_COUNT; + refreshSettings(); initCubeFree(); } @@ -222,25 +223,21 @@ void LLReflectionMapManager::update() resume(); } - static LLCachedControl sDetail(gSavedSettings, "RenderReflectionProbeDetail", -1); - static LLCachedControl sLevel(gSavedSettings, "RenderReflectionProbeLevel", 3); - static LLCachedControl sReflectionProbeCount(gSavedSettings, "RenderReflectionProbeCount", 256U); - static LLCachedControl sProbeDynamicAllocation(gSavedSettings, "RenderReflectionProbeDynamicAllocation", -1); mResetFade = llmin((F32)(mResetFade + gFrameIntervalSeconds * 2.f), 1.f); { U32 probe_count_temp = mDynamicProbeCount; - if (sProbeDynamicAllocation > -1) + if (mRenderReflectionProbeDynamicAllocation > -1) { - if (sLevel == 0) + if (mRenderReflectionProbeLevel == 0) { mDynamicProbeCount = 1; } - else if (sLevel == 1) + else if (mRenderReflectionProbeLevel == 1) { mDynamicProbeCount = (U32)mProbes.size(); } - else if (sLevel == 2) + else if (mRenderReflectionProbeLevel == 2) { mDynamicProbeCount = llmax((U32)mProbes.size(), 128); } @@ -249,20 +246,20 @@ void LLReflectionMapManager::update() mDynamicProbeCount = 256; } - if (sProbeDynamicAllocation > 1) + if (mRenderReflectionProbeDynamicAllocation > 1) { // Round mDynamicProbeCount to the nearest increment of 16 - mDynamicProbeCount = ((mDynamicProbeCount + sProbeDynamicAllocation / 2) / sProbeDynamicAllocation) * 16; - mDynamicProbeCount = llclamp(mDynamicProbeCount, 1, sReflectionProbeCount); + mDynamicProbeCount = ((mDynamicProbeCount + mRenderReflectionProbeDynamicAllocation / 2) / mRenderReflectionProbeDynamicAllocation) * 16; + mDynamicProbeCount = llclamp(mDynamicProbeCount, 1, mRenderReflectionProbeCount); } else { - mDynamicProbeCount = llclamp(mDynamicProbeCount + sProbeDynamicAllocation, 1, sReflectionProbeCount); + mDynamicProbeCount = llclamp(mDynamicProbeCount + mRenderReflectionProbeDynamicAllocation, 1, mRenderReflectionProbeCount); } } else { - mDynamicProbeCount = sReflectionProbeCount; + mDynamicProbeCount = mRenderReflectionProbeCount; } mDynamicProbeCount = llmin(mDynamicProbeCount, LL_MAX_REFLECTION_PROBE_COUNT); @@ -328,7 +325,7 @@ void LLReflectionMapManager::update() bool did_update = false; - bool realtime = sDetail >= (S32)LLReflectionMapManager::DetailLevel::REALTIME; + bool realtime = mRenderReflectionProbeDetail >= (S32)LLReflectionMapManager::DetailLevel::REALTIME; LLReflectionMap* closestDynamic = nullptr; @@ -457,7 +454,7 @@ void LLReflectionMapManager::update() closestDynamic = probe; } - if (sLevel == 0) + if (mRenderReflectionProbeLevel == 0) { // only update default probe when coverage is set to none llassert(probe == mDefaultProbe); @@ -489,12 +486,12 @@ void LLReflectionMapManager::update() static LLCachedControl sUpdatePeriod(gSavedSettings, "RenderDefaultProbeUpdatePeriod", 2.f); if ((gFrameTimeSeconds - mDefaultProbe->mLastUpdateTime) < sUpdatePeriod) { - if (sLevel == 0) + if (mRenderReflectionProbeLevel == 0) { // when probes are disabled don't update the default probe more often than the prescribed update period oldestProbe = nullptr; } } - else if (sLevel > 0) + else if (mRenderReflectionProbeLevel > 0) { // when probes are enabled don't update the default probe less often than the prescribed update period oldestProbe = mDefaultProbe; } @@ -520,6 +517,14 @@ void LLReflectionMapManager::update() } } +void LLReflectionMapManager::refreshSettings() +{ + mRenderReflectionProbeDetail = gSavedSettings.getS32("RenderReflectionProbeDetail"); + mRenderReflectionProbeLevel = gSavedSettings.getS32("RenderReflectionProbeLevel"); + mRenderReflectionProbeCount = gSavedSettings.getU32("RenderReflectionProbeCount"); + mRenderReflectionProbeDynamicAllocation = gSavedSettings.getS32("RenderReflectionProbeDynamicAllocation"); +} + LLReflectionMap* LLReflectionMapManager::addProbe(LLSpatialGroup* group) { if (gGLManager.mGLVersion < 4.05f || !LLPipeline::sReflectionProbesEnabled) @@ -782,7 +787,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) } else { - llassert(gSavedSettings.getS32("RenderReflectionProbeLevel") > 0); // should never update a probe that's not the default probe if reflection coverage is none + llassert(mRenderReflectionProbeLevel > 0); // should never update a probe that's not the default probe if reflection coverage is none probe->update(mRenderTarget.getWidth(), face); } diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h index 0719c281345..5daed7d1cf1 100644 --- a/indra/newview/llreflectionmapmanager.h +++ b/indra/newview/llreflectionmapmanager.h @@ -110,6 +110,8 @@ class alignas(16) LLReflectionMapManager // maintain reflection probes void update(); + void refreshSettings(); + // add a probe for the given spatial group LLReflectionMap* addProbe(LLSpatialGroup* group = nullptr); @@ -248,6 +250,12 @@ class alignas(16) LLReflectionMapManager U32 mDynamicProbeCount; + // cached settings from gSavedSettings + S32 mRenderReflectionProbeDetail = -1; + S32 mRenderReflectionProbeLevel = 3; + U32 mRenderReflectionProbeCount = 256U; + S32 mRenderReflectionProbeDynamicAllocation = -1; + // resolution of reflection probes U32 mProbeResolution = 128; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 598ad89907c..d39805f4c77 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -447,6 +447,7 @@ static bool handleRenderDynamicLODChanged(const LLSD& newvalue) static bool handleReflectionProbeDetailChanged(const LLSD& newvalue) { + gPipeline.mReflectionMapManager.refreshSettings(); if (gPipeline.isInit()) { LLPipeline::refreshCachedSettings(); @@ -459,6 +460,12 @@ static bool handleReflectionProbeDetailChanged(const LLSD& newvalue) return true; } +static bool handleReflectionProbeCountChanged(const LLSD& newvalue) +{ + gPipeline.mReflectionMapManager.refreshSettings(); + return true; +} + #if LL_DARWIN static bool handleAppleUseMultGLChanged(const LLSD& newvalue) { @@ -836,6 +843,7 @@ void settings_setup_listeners() setting_setup_signal_listener(gSavedSettings, "RenderResolutionDivisor", handleRenderResolutionDivisorChanged); setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeLevel", handleReflectionProbeDetailChanged); setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeDetail", handleReflectionProbeDetailChanged); + setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeCount", handleReflectionProbeCountChanged); setting_setup_signal_listener(gSavedSettings, "RenderReflectionsEnabled", handleReflectionProbeDetailChanged); #if LL_DARWIN setting_setup_signal_listener(gSavedSettings, "RenderAppleUseMultGL", handleAppleUseMultGLChanged); From bbdb46a833c1c3d8c26aa1a9a69bf05f4b065853 Mon Sep 17 00:00:00 2001 From: Dan Linden <119471733+Dan-Linden@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:41:07 -0700 Subject: [PATCH 098/145] Update qatest.yaml Removed dan's z600 windows machine from the matrix. Added dan's mac, caleb's mac and kurt's windows machines. --- .github/workflows/qatest.yaml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/qatest.yaml b/.github/workflows/qatest.yaml index 457e915726b..e19dce2709a 100644 --- a/.github/workflows/qatest.yaml +++ b/.github/workflows/qatest.yaml @@ -47,13 +47,21 @@ jobs: artifact: Windows-installer install-path: 'C:\viewer-automation-main' - os: windows - runner: qa-windows-z600-dan + runner: qa-windows-asus-kurt artifact: Windows-installer install-path: 'C:\viewer-automation-main' + - os: mac + runner: qa-mac-dan + artifact: macOS-installer + install-path: '$HOME/Documents/viewer-automation' - os: mac runner: qa-mac-atlas artifact: macOS-installer install-path: '$HOME/Documents/viewer-automation' + - os: mac + runner: qa-mac-caleb + artifact: macOS-installer + install-path: '$HOME/Documents/viewer-automation' fail-fast: false runs-on: [self-hosted, "${{ matrix.runner }}"] From e33439e5238e9d2945aa99515c0206d827cc0910 Mon Sep 17 00:00:00 2001 From: Dan Linden <119471733+Dan-Linden@users.noreply.github.com> Date: Tue, 26 Aug 2025 15:18:10 -0700 Subject: [PATCH 099/145] Update qatest.yaml corrected kurt's machine name to qa-windows-kurt --- .github/workflows/qatest.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qatest.yaml b/.github/workflows/qatest.yaml index e19dce2709a..b6883d88d43 100644 --- a/.github/workflows/qatest.yaml +++ b/.github/workflows/qatest.yaml @@ -47,7 +47,7 @@ jobs: artifact: Windows-installer install-path: 'C:\viewer-automation-main' - os: windows - runner: qa-windows-asus-kurt + runner: qa-windows-kurt artifact: Windows-installer install-path: 'C:\viewer-automation-main' - os: mac From 0fc42e951f99182b080c7187455d6a4da602441b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 27 Aug 2025 01:42:36 +0300 Subject: [PATCH 100/145] #4608 Crash at LLJoint::findJoint 'this' is null inside findJoint according to bugsplat so likely mRoot was not initialized yet. --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 9e8ed3bb437..997fc28333a 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2460,7 +2460,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat LLPointer info = nullptr; info = new LLMeshSkinInfo(mesh_id, skin); - if (isAgentAvatarValid()) + if (isAgentAvatarValid() && gAgentAvatarp->mInitFlags != 0) { // joint numbers are consistent inside LLVOAvatar and animations, but inconsistent inside meshes, // generate a map of mesh joint numbers to LLVOAvatar joint numbers LLSkinningUtil::initJointNums(info, gAgentAvatarp); From 87ec630053aadcb5b5f6104f7d083acf4609e2e9 Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Wed, 27 Aug 2025 15:30:32 -0700 Subject: [PATCH 101/145] PUll in Dullahan 1.21 that contains additional updates for the macOS version which should help with the slow media startup issue --- autobuild.xml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index ffea5916e9d..2931b789028 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -448,11 +448,11 @@ archive hash - 67f6df74e64ec7706b59192dbdef1d0da2754127 + d44256458ff0ef4db4c91e8e8cc83e8f98b4f1b8 hash_algorithm sha1 url - https://github.com/secondlife/dullahan/releases/download/v1.20.0-CEF_139.0.28a/dullahan-1.20.0.202508222243_139.0.28_g55ab8a8_chromium-139.0.7258.139-darwin64-17167490569.tar.zst + https://github.com/secondlife/dullahan/releases/download/v1.21.0-CEF_139.0.28/dullahan-1.21.0.202508272158_139.0.28_g55ab8a8_chromium-139.0.7258.139-darwin64-17279703032.tar.zst name darwin64 @@ -476,11 +476,11 @@ archive hash - 7fe15918eeeb5121b6c5af9427f581a775b88758 + 9d5af766a87052808e4062978504e9af124fb558 hash_algorithm sha1 url - https://github.com/secondlife/dullahan/releases/download/v1.20.0-CEF_139.0.28a/dullahan-1.20.0.202508222244_139.0.28_g55ab8a8_chromium-139.0.7258.139-windows64-17167490569.tar.zst + https://github.com/secondlife/dullahan/releases/download/v1.21.0-CEF_139.0.28/dullahan-1.21.0.202508272159_139.0.28_g55ab8a8_chromium-139.0.7258.139-windows64-17279703032.tar.zst name windows64 @@ -493,7 +493,7 @@ copyright Copyright (c) 2017, Linden Research, Inc. version - 1.20.0.202508222243_139.0.28_g55ab8a8_chromium-139.0.7258.139 + 1.21.0.202508272158_139.0.28_g55ab8a8_chromium-139.0.7258.139 name dullahan description @@ -1477,12 +1477,12 @@ windows64 - copyright - Copyright (c) 2010, Linden Research, Inc. license internal license_file LICENSES/llphysicsextensions.txt + copyright + Copyright (c) 2010, Linden Research, Inc. version 1.0.11137145495 name @@ -2332,14 +2332,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors threejs - copyright - Copyright © 2010-2021 three.js authors - license - MIT - license_file - LICENSES/THREEJS_LICENSE.txt - name - threejs platforms common @@ -2357,8 +2349,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors common + license + MIT + license_file + LICENSES/THREEJS_LICENSE.txt + copyright + Copyright © 2010-2021 three.js authors version 0.132.2 + name + threejs tinygltf From e629bf05d6212613083c8ccb2858085926f38902 Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 27 Aug 2025 22:36:55 -0400 Subject: [PATCH 102/145] Changes to support dullahan 1.21 undo/redo/delete/select all edit handlers --- indra/llplugin/llpluginclassmedia.cpp | 50 ++++++++++++ indra/llplugin/llpluginclassmedia.h | 18 +++++ indra/media_plugins/cef/media_plugin_cef.cpp | 59 +++++++++++++- indra/newview/llmediactrl.cpp | 10 ++- indra/newview/llmediactrl.h | 1 + indra/newview/llviewermedia.cpp | 80 +++++++++++++++++++ indra/newview/llviewermedia.h | 12 +++ .../skins/default/xui/en/menu_media_ctrl.xml | 8 ++ 8 files changed, 236 insertions(+), 2 deletions(-) diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 8a356da93a9..77a4b08af55 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -132,9 +132,13 @@ void LLPluginClassMedia::reset() mLastMouseY = 0; mStatus = LLPluginClassMediaOwner::MEDIA_NONE; mSleepTime = 1.0f / 100.0f; + mCanUndo = false; + mCanRedo = false; mCanCut = false; mCanCopy = false; mCanPaste = false; + mCanDoDelete = false; + mCanSelectAll = false; mMediaName.clear(); mMediaDescription.clear(); mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f); @@ -907,6 +911,18 @@ void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, sendMessage(message); } +void LLPluginClassMedia::undo() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_undo"); + sendMessage(message); +} + +void LLPluginClassMedia::redo() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_redo"); + sendMessage(message); +} + void LLPluginClassMedia::cut() { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); @@ -925,6 +941,24 @@ void LLPluginClassMedia::paste() sendMessage(message); } +void LLPluginClassMedia::doDelete() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_delete"); + sendMessage(message); +} + +void LLPluginClassMedia::selectAll() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_select_all"); + sendMessage(message); +} + +void LLPluginClassMedia::showPageSource() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_show_source"); + sendMessage(message); +} + void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path_cache, const std::string &username, const std::string &user_data_path_cef_log) @@ -1178,6 +1212,14 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) } else if(message_name == "edit_state") { + if(message.hasValue("undo")) + { + mCanUndo = message.getValueBoolean("undo"); + } + if(message.hasValue("redo")) + { + mCanRedo = message.getValueBoolean("redo"); + } if(message.hasValue("cut")) { mCanCut = message.getValueBoolean("cut"); @@ -1190,6 +1232,14 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { mCanPaste = message.getValueBoolean("paste"); } + if (message.hasValue("delete")) + { + mCanDoDelete = message.getValueBoolean("delete"); + } + if (message.hasValue("select_all")) + { + mCanSelectAll = message.getValueBoolean("select_all"); + } } else if(message_name == "name_text") { diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index d74b790d8f7..292d9344195 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -201,6 +201,12 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; } + void undo(); + bool canUndo() const { return mCanUndo; }; + + void redo(); + bool canRedo() const { return mCanRedo; }; + void cut(); bool canCut() const { return mCanCut; }; @@ -210,6 +216,14 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner void paste(); bool canPaste() const { return mCanPaste; }; + void doDelete(); + bool canDoDelete() const { return mCanDoDelete; }; + + void selectAll(); + bool canSelectAll() const { return mCanSelectAll; }; + + void showPageSource(); + // These can be called before init(), and they will be queued and sent before the media init message. void setUserDataPath(const std::string &user_data_path_cache, const std::string &username, const std::string &user_data_path_cef_log); void setLanguageCode(const std::string &language_code); @@ -419,9 +433,13 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner F64 mSleepTime; + bool mCanUndo; + bool mCanRedo; bool mCanCut; bool mCanCopy; bool mCanPaste; + bool mCanDoDelete; + bool mCanSelectAll; std::string mMediaName; std::string mMediaDescription; diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 52df4a96859..caf804f915d 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -106,9 +106,13 @@ class MediaPluginCEF : std::string mAuthUsername; std::string mAuthPassword; bool mAuthOK; + bool mCanUndo; + bool mCanRedo; bool mCanCut; bool mCanCopy; bool mCanPaste; + bool mCanDelete; + bool mCanSelectAll; std::string mRootCachePath; std::string mCefLogFile; bool mCefLogVerbose; @@ -144,9 +148,13 @@ MediaPluginBase(host_send_func, host_user_data) mAuthUsername = ""; mAuthPassword = ""; mAuthOK = false; + mCanUndo = false; + mCanRedo = false; mCanCut = false; mCanCopy = false; mCanPaste = false; + mCanDelete = false; + mCanSelectAll = false; mCefLogFile = ""; mCefLogVerbose = false; mPickedFiles.clear(); @@ -940,6 +948,14 @@ void MediaPluginCEF::receiveMessage(const char* message_string) { authResponse(message_in); } + if (message_name == "edit_undo") + { + mCEFLib->editUndo(); + } + if (message_name == "edit_redo") + { + mCEFLib->editRedo(); + } if (message_name == "edit_cut") { mCEFLib->editCut(); @@ -952,6 +968,18 @@ void MediaPluginCEF::receiveMessage(const char* message_string) { mCEFLib->editPaste(); } + if (message_name == "edit_delete") + { + mCEFLib->editDelete(); + } + if (message_name == "edit_select_all") + { + mCEFLib->editSelectAll(); + } + if (message_name == "edit_show_source") + { + mCEFLib->viewSource(); + } } else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) { @@ -1103,14 +1131,31 @@ void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD // void MediaPluginCEF::checkEditState() { + bool can_undo = mCEFLib->editCanUndo(); + bool can_redo = mCEFLib->editCanRedo(); bool can_cut = mCEFLib->editCanCut(); bool can_copy = mCEFLib->editCanCopy(); bool can_paste = mCEFLib->editCanPaste(); + bool can_delete = mCEFLib->editCanDelete(); + bool can_select_all = mCEFLib->editCanSelectAll(); - if ((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste)) + if ((can_undo != mCanUndo) || (can_redo != mCanRedo) || (can_cut != mCanCut) || (can_copy != mCanCopy) + || (can_paste != mCanPaste) || (can_delete != mCanDelete) || (can_select_all != mCanSelectAll)) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state"); + if (can_undo != mCanUndo) + { + mCanUndo = can_undo; + message.setValueBoolean("undo", can_undo); + } + + if (can_redo != mCanRedo) + { + mCanRedo = can_redo; + message.setValueBoolean("redo", can_redo); + } + if (can_cut != mCanCut) { mCanCut = can_cut; @@ -1129,6 +1174,18 @@ void MediaPluginCEF::checkEditState() message.setValueBoolean("paste", can_paste); } + if (can_delete != mCanDelete) + { + mCanDelete = can_delete; + message.setValueBoolean("delete", can_delete); + } + + if (can_select_all != mCanSelectAll) + { + mCanSelectAll = can_select_all; + message.setValueBoolean("select_all", can_select_all); + } + sendMessage(message); } } diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 202008f7f93..c7b60b2fd56 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -347,6 +347,7 @@ bool LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask ) { LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); + registar.add("Open.ShowSource", boost::bind(&LLMediaCtrl::onShowSource, this)); // stinson 05/05/2014 : use this as the parent of the context menu if the static menu // container has yet to be created @@ -364,8 +365,9 @@ bool LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask ) { // hide/show debugging options bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging"); + menu->setItemVisible("debug_separator", media_plugin_debugging_enabled); menu->setItemVisible("open_webinspector", media_plugin_debugging_enabled ); - menu->setItemVisible("debug_separator", media_plugin_debugging_enabled ); + menu->setItemVisible("show_page_source", media_plugin_debugging_enabled); menu->show(x, y); LLMenuGL::showPopup(this, menu, x, y); @@ -444,6 +446,12 @@ void LLMediaCtrl::onOpenWebInspector() mMediaSource->getMediaPlugin()->showWebInspector( true ); } +void LLMediaCtrl::onShowSource() +{ + if (mMediaSource && mMediaSource->hasMedia()) + mMediaSource->getMediaPlugin()->showPageSource(); +} + //////////////////////////////////////////////////////////////////////////////// // bool LLMediaCtrl::handleKeyHere( KEY key, MASK mask ) diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 9f9564af46c..a644ef30719 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -171,6 +171,7 @@ class LLMediaCtrl : // right click debugging item void onOpenWebInspector(); + void onShowSource(); LLUUID getTextureID() {return mMediaTextureID;} diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index c6bc252efd2..89861d74bc5 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -3508,6 +3508,46 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla } } +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::undo() +{ + if (mMediaSource) + mMediaSource->undo(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +bool +LLViewerMediaImpl::canUndo() const +{ + if (mMediaSource) + return mMediaSource->canUndo(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::redo() +{ + if (mMediaSource) + mMediaSource->redo(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +bool +LLViewerMediaImpl::canRedo() const +{ + if (mMediaSource) + return mMediaSource->canRedo(); + else + return FALSE; +} + //////////////////////////////////////////////////////////////////////////////// // virtual void @@ -3568,6 +3608,46 @@ LLViewerMediaImpl::canPaste() const return false; } +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::doDelete() +{ + if (mMediaSource) + mMediaSource->doDelete(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +bool +LLViewerMediaImpl::canDoDelete() const +{ + if (mMediaSource) + return mMediaSource->canDoDelete(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::selectAll() +{ + if (mMediaSource) + mMediaSource->selectAll(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +bool +LLViewerMediaImpl::canSelectAll() const +{ + if (mMediaSource) + return mMediaSource->canSelectAll(); + else + return FALSE; +} + void LLViewerMediaImpl::setUpdated(bool updated) { mIsUpdated = updated ; diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 5753615a432..c17cf598159 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -341,6 +341,12 @@ class LLViewerMediaImpl /*virtual*/ void handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent); // LLEditMenuHandler overrides + /*virtual*/ void undo(); + /*virtual*/ bool canUndo() const; + + /*virtual*/ void redo(); + /*virtual*/ bool canRedo() const; + /*virtual*/ void cut(); /*virtual*/ bool canCut() const; @@ -350,6 +356,12 @@ class LLViewerMediaImpl /*virtual*/ void paste(); /*virtual*/ bool canPaste() const; + /*virtual*/ void doDelete(); + /*virtual*/ bool canDoDelete() const; + + /*virtual*/ void selectAll(); + /*virtual*/ bool canSelectAll() const; + void addObject(LLVOVolume* obj) ; void removeObject(LLVOVolume* obj) ; const std::list< LLVOVolume* >* getObjectList() const ; diff --git a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml index f9864637a00..e687ae93e8d 100644 --- a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml +++ b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml @@ -40,4 +40,12 @@ + + + From 536c821c091be7020c614857e1fd220203f6ab23 Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 27 Aug 2025 23:05:40 -0400 Subject: [PATCH 103/145] MacOS companion changes for dullahan 1.21 including package structure and linkage fixes --- indra/cmake/00-Common.cmake | 3 + indra/cmake/CEFPlugin.cmake | 1 - indra/cmake/PluginAPI.cmake | 4 + indra/llfilesystem/lldir_mac.cpp | 2 +- indra/llplugin/CMakeLists.txt | 2 +- indra/llplugin/llpluginclassmedia.h | 7 +- indra/llplugin/slplugin/CMakeLists.txt | 28 ++-- indra/media_plugins/base/CMakeLists.txt | 2 +- indra/media_plugins/cef/CMakeLists.txt | 10 +- indra/media_plugins/example/CMakeLists.txt | 2 +- indra/media_plugins/libvlc/CMakeLists.txt | 2 +- .../libvlc/media_plugin_libvlc.cpp | 2 +- indra/newview/CMakeLists.txt | 6 +- indra/newview/viewer_manifest.py | 123 +++--------------- 14 files changed, 52 insertions(+), 142 deletions(-) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index c895f423624..5943e0b5734 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -162,6 +162,9 @@ endif (LINUX) if (DARWIN) + # Use rpath loading on macos + set(CMAKE_MACOSX_RPATH TRUE) + # Warnings should be fatal -- thanks, Nicky Perian, for spotting reversed default set(CLANG_DISABLE_FATAL_WARNINGS OFF) set(CMAKE_CXX_LINK_FLAGS "-Wl,-headerpad_max_install_names,-search_paths_first") diff --git a/indra/cmake/CEFPlugin.cmake b/indra/cmake/CEFPlugin.cmake index 9b77becf29f..e27929fa088 100644 --- a/indra/cmake/CEFPlugin.cmake +++ b/indra/cmake/CEFPlugin.cmake @@ -29,7 +29,6 @@ elseif (DARWIN) ${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a ${ARCH_PREBUILT_DIRS_RELEASE}/libdullahan.a ${APPKIT_LIBRARY} - "-F ${CEF_LIBRARY}" ) elseif (LINUX) diff --git a/indra/cmake/PluginAPI.cmake b/indra/cmake/PluginAPI.cmake index 114415e514b..a2bf13db2c9 100644 --- a/indra/cmake/PluginAPI.cmake +++ b/indra/cmake/PluginAPI.cmake @@ -1,5 +1,7 @@ # -*- cmake -*- +include(OpenGL) + add_library( ll::pluginlibraries INTERFACE IMPORTED ) if (WINDOWS) @@ -13,4 +15,6 @@ if (WINDOWS) ) endif (WINDOWS) +target_link_libraries( ll::pluginlibraries INTERFACE OpenGL::GL) +target_include_directories( ll::pluginlibraries INTERFACE ${CMAKE_SOURCE_DIR}/llimage ${CMAKE_SOURCE_DIR}/llrender) diff --git a/indra/llfilesystem/lldir_mac.cpp b/indra/llfilesystem/lldir_mac.cpp index b9be75c528f..2db1b6ec5d4 100644 --- a/indra/llfilesystem/lldir_mac.cpp +++ b/indra/llfilesystem/lldir_mac.cpp @@ -149,7 +149,7 @@ LLDir_Mac::LLDir_Mac() mWorkingDir = getCurPath(); - mLLPluginDir = mAppRODataDir + mDirDelimiter + "llplugin"; + mLLPluginDir = mAppRODataDir + mDirDelimiter + "SLPlugin.app" + mDirDelimiter + "Contents" + mDirDelimiter + "Frameworks"; } } diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt index 14a69afe6eb..f7f8c08adb4 100644 --- a/indra/llplugin/CMakeLists.txt +++ b/indra/llplugin/CMakeLists.txt @@ -43,6 +43,6 @@ list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES}) add_library (llplugin ${llplugin_SOURCE_FILES}) target_include_directories( llplugin INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries( llplugin llcommon llmath llrender llmessage ) +target_link_libraries( llplugin llcommon llmath llmessage llxml ) add_subdirectory(slplugin) diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 292d9344195..71522bcd7d5 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -29,7 +29,6 @@ #ifndef LL_LLPLUGINCLASSMEDIA_H #define LL_LLPLUGINCLASSMEDIA_H -#include "llgltypes.h" #include "llpluginprocessparent.h" #include "llrect.h" #include "llpluginclassmediaowner.h" @@ -365,9 +364,9 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true S32 mRequestedTextureDepth; - LLGLenum mRequestedTextureInternalFormat; - LLGLenum mRequestedTextureFormat; - LLGLenum mRequestedTextureType; + U32 mRequestedTextureInternalFormat; + U32 mRequestedTextureFormat; + U32 mRequestedTextureType; bool mRequestedTextureSwapBytes; bool mRequestedTextureCoordsOpenGL; diff --git a/indra/llplugin/slplugin/CMakeLists.txt b/indra/llplugin/slplugin/CMakeLists.txt index 0ea6495eaca..e639e522afb 100644 --- a/indra/llplugin/slplugin/CMakeLists.txt +++ b/indra/llplugin/slplugin/CMakeLists.txt @@ -30,18 +30,6 @@ add_executable(SLPlugin ${SLPlugin_SOURCE_FILES} ) -if (WINDOWS) -set_target_properties(SLPlugin - PROPERTIES - LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMTD\"" - ) -else () -set_target_properties(SLPlugin - PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist - ) -endif () - target_link_libraries(SLPlugin llplugin llmessage @@ -49,7 +37,19 @@ target_link_libraries(SLPlugin ll::pluginlibraries ) -if (DARWIN) +if (WINDOWS) + set_target_properties(SLPlugin + PROPERTIES + LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMTD\"" + ) +elseif (DARWIN) + set_target_properties(SLPlugin + PROPERTIES + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_RPATH "@executable_path/../../../../Frameworks;@executable_path/../Frameworks;@executable_path/../Frameworks/plugins" + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist + ) + # Make sure the app bundle has a Resources directory (it will get populated by viewer-manifest.py later) add_custom_command( TARGET SLPlugin POST_BUILD @@ -58,7 +58,7 @@ if (DARWIN) -p ${CMAKE_CURRENT_BINARY_DIR}/$,$,>/SLPlugin.app/Contents/Resources ) -endif (DARWIN) +endif () if (LL_TESTS) ll_deploy_sharedlibs_command(SLPlugin) diff --git a/indra/media_plugins/base/CMakeLists.txt b/indra/media_plugins/base/CMakeLists.txt index 64b6a4228d2..23f503c3458 100644 --- a/indra/media_plugins/base/CMakeLists.txt +++ b/indra/media_plugins/base/CMakeLists.txt @@ -34,5 +34,5 @@ add_library(media_plugin_base ${media_plugin_base_SOURCE_FILES} ) -target_link_libraries( media_plugin_base llplugin ) +target_link_libraries( media_plugin_base llplugin ll::pluginlibraries) target_include_directories( media_plugin_base INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt index 0d1a8339366..ebcf67576dc 100644 --- a/indra/media_plugins/cef/CMakeLists.txt +++ b/indra/media_plugins/cef/CMakeLists.txt @@ -77,16 +77,8 @@ if (DARWIN) PROPERTIES PREFIX "" BUILD_WITH_INSTALL_RPATH 1 - INSTALL_NAME_DIR "@executable_path" + INSTALL_RPATH "@executable_path/../Frameworks" LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" ) - add_custom_command(TARGET media_plugin_cef - POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "@executable_path/Chromium Embedded Framework" - "@executable_path/../../../../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" - "$" - VERBATIM - COMMENT "Fixing path to CEF Framework" - ) - endif (DARWIN) diff --git a/indra/media_plugins/example/CMakeLists.txt b/indra/media_plugins/example/CMakeLists.txt index 41e2353f31c..278dac8c336 100644 --- a/indra/media_plugins/example/CMakeLists.txt +++ b/indra/media_plugins/example/CMakeLists.txt @@ -47,7 +47,7 @@ if (DARWIN) PROPERTIES PREFIX "" BUILD_WITH_INSTALL_RPATH 1 - INSTALL_NAME_DIR "@executable_path" + INSTALL_RPATH "@executable_path/../Frameworks" LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" ) diff --git a/indra/media_plugins/libvlc/CMakeLists.txt b/indra/media_plugins/libvlc/CMakeLists.txt index 202cbed96e6..f9e0810df26 100644 --- a/indra/media_plugins/libvlc/CMakeLists.txt +++ b/indra/media_plugins/libvlc/CMakeLists.txt @@ -50,7 +50,7 @@ if (DARWIN) PROPERTIES PREFIX "" BUILD_WITH_INSTALL_RPATH 1 - INSTALL_NAME_DIR "@executable_path" + INSTALL_RPATH "@executable_path/../Frameworks" LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" ) diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp index 4240613a0c1..ad0ecaf4abf 100644 --- a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp +++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp @@ -174,7 +174,7 @@ void MediaPluginLibVLC::initVLC() }; #if LL_DARWIN - setenv("VLC_PLUGIN_PATH", ".", 1); + setenv("VLC_PLUGIN_PATH", "./plugins", 1); #endif int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index f2aec208a1e..40b6b357044 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2156,10 +2156,8 @@ if (DARWIN) PROPERTIES OUTPUT_NAME "${product}" # From Contents/MacOS/SecondLife, look in Contents/Frameworks - INSTALL_RPATH "@loader_path/../Frameworks" - # SIGH, as of 2018-05-24 (cmake 3.11.1) the INSTALL_RPATH property simply - # does not work. Try this: - LINK_FLAGS "-rpath @loader_path/../Frameworks" + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_RPATH "@executable_path/../Frameworks" MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist" XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${MACOSX_BUNDLE_GUI_IDENTIFIER}" ) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 1146922d5dc..666f7675ac0 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -865,9 +865,6 @@ def construct(self): # CEF framework goes inside Contents/Frameworks. # Remember where we parked this car. with self.prefix(src="", dst="Frameworks"): - CEF_framework = "Chromium Embedded Framework.framework" - self.path2basename(relpkgdir, CEF_framework) - CEF_framework = self.dst_path_of(CEF_framework) if self.args.get('bugsplat'): self.path2basename(relpkgdir, "BugsplatMac.framework") @@ -1065,113 +1062,31 @@ def path_optional(src, dst): # Dullahan helper apps go inside SLPlugin.app with self.prefix(dst=os.path.join( "SLPlugin.app", "Contents", "Frameworks")): - - frameworkname = 'Chromium Embedded Framework' - - # This code constructs a relative symlink from the - # target framework folder back to the real CEF framework. - # It needs to be relative so that the symlink still works when - # (as is normal) the user moves the app bundle out of the DMG - # and into the /Applications folder. Note we pass catch=False, - # letting the uncaught exception terminate the process, since - # without this symlink, Second Life web media can't possibly work. - - # It might seem simpler just to symlink Frameworks back to - # the parent of Chromimum Embedded Framework.framework. But - # that would create a symlink cycle, which breaks our - # packaging step. So make a symlink from Chromium Embedded - # Framework.framework to the directory of the same name, which - # is NOT an ancestor of the symlink. - - # from SLPlugin.app/Contents/Frameworks/Chromium Embedded - # Framework.framework back to - # $viewer_app/Contents/Frameworks/Chromium Embedded Framework.framework - SLPlugin_framework = self.relsymlinkf(CEF_framework, catch=False) - - # for all the multiple CEF/Dullahan (as of CEF 76) helper app bundles we need: - for helper in ( - "DullahanHelper", - "DullahanHelper (GPU)", - "DullahanHelper (Renderer)", - "DullahanHelper (Plugin)", - ): - # app is the directory name of the app bundle, with app/Contents/MacOS/helper as the executable - app = helper + ".app" - - # copy DullahanHelper.app - self.path2basename(relpkgdir, app) - - # and fix that up with a Frameworks/CEF symlink too - with self.prefix(dst=os.path.join( - app, 'Contents', 'Frameworks')): - # from Dullahan Helper *.app/Contents/Frameworks/Chromium Embedded - # Framework.framework back to - # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework - # Since SLPlugin_framework is itself a - # symlink, don't let relsymlinkf() resolve -- - # explicitly call relpath(symlink=True) and - # create that symlink here. - helper_framework = \ - self.symlinkf(self.relpath(SLPlugin_framework, symlink=True), catch=False) - - # change_command includes install_name_tool, the - # -change subcommand and the old framework rpath - # stamped into the executable. To use it with - # run_command(), we must still append the new - # framework path and the pathname of the - # executable to change. - change_command = [ - 'install_name_tool', '-change', - '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework'] - - with self.prefix(dst=os.path.join( - app, 'Contents', 'MacOS')): - # Now self.get_dst_prefix() is, at runtime, - # @executable_path. Locate the helper app - # framework (which is a symlink) from here. - newpath = os.path.join( - '@executable_path', - self.relpath(helper_framework, symlink=True), - frameworkname) - # and restamp the Dullahan Helper executable itself - self.run_command( - change_command + - [newpath, self.dst_path_of(helper)]) - - # SLPlugin plugins - with self.prefix(dst="llplugin"): - dylibexecutable = 'media_plugin_cef.dylib' + # copy CEF plugin self.path2basename("../media_plugins/cef/" + self.args['configuration'], - dylibexecutable) - - # Do this install_name_tool *after* media plugin is copied over. - # Locate the framework lib executable -- relative to - # SLPlugin.app/Contents/MacOS, which will be our - # @executable_path at runtime! - newpath = os.path.join( - '@executable_path', - self.relpath(SLPlugin_framework, executable_path["SLPlugin.app"], - symlink=True), - frameworkname) - # restamp media_plugin_cef.dylib - self.run_command( - change_command + - [newpath, self.dst_path_of(dylibexecutable)]) - - # copy LibVLC plugin itself - dylibexecutable = 'media_plugin_libvlc.dylib' - self.path2basename("../media_plugins/libvlc/" + self.args['configuration'], dylibexecutable) - # add @rpath for the correct LibVLC subfolder - self.run_command(['install_name_tool', '-add_rpath', '@loader_path/lib', self.dst_path_of(dylibexecutable)]) - - # copy LibVLC dynamic libraries - with self.prefix(src=relpkgdir, dst="lib"): + "media_plugin_cef.dylib") + + # copy LibVLC plugin + self.path2basename("../media_plugins/libvlc/" + self.args['configuration'], + "media_plugin_libvlc.dylib") + + # CEF framework and vlc libraries goes inside Contents/Frameworks. + with self.prefix(src=os.path.join(pkgdir, 'lib', 'release')): + self.path("Chromium Embedded Framework.framework") + self.path("DullahanHelper.app") + self.path("DullahanHelper (Alerts).app") + self.path("DullahanHelper (GPU).app") + self.path("DullahanHelper (Renderer).app") + self.path("DullahanHelper (Plugin).app") + + # Copy libvlc self.path( "libvlc*.dylib*" ) # copy LibVLC plugins folder - with self.prefix(src='plugins', dst=""): + with self.prefix(src='plugins', dst="plugins"): self.path( "*.dylib" ) self.path( "plugins.dat" ) + def package_finish(self): imagename = self.installer_base_name() self.set_github_output('imagename', imagename) From dae43ad532579e849aa191fba4fdb3478a455840 Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 27 Aug 2025 23:05:58 -0400 Subject: [PATCH 104/145] Fix cmake to ${CMAKE_COMMAND} to avoid cmake error --- indra/test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index 745c0eedf81..f80286a630c 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -114,7 +114,7 @@ if (LL_TESTS) # but the CMake $ generator expression isn't evaluated by # CREATE_LINK, so fudge it. add_custom_command( TARGET lltest POST_BUILD - COMMAND cmake -E create_symlink ${SHARED_LIB_STAGING_DIR} ${CMAKE_BINARY_DIR}/test/Resources + COMMAND ${CMAKE_COMMAND} -E create_symlink ${SHARED_LIB_STAGING_DIR} ${CMAKE_BINARY_DIR}/test/Resources ) endif() endif (LL_TESTS) From 77d71dec863e28323bcafb1573cd1ecd54fe3049 Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 28 Aug 2025 00:43:38 -0400 Subject: [PATCH 105/145] Fix up universal build --- autobuild.xml | 2 +- build.sh | 2 +- indra/cmake/OpenJPEG.cmake | 4 +++- indra/cmake/Variables.cmake | 6 +++--- indra/newview/viewer_manifest.py | 21 --------------------- 5 files changed, 8 insertions(+), 27 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index fe4caace0bc..0bfb8b67f24 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -3171,7 +3171,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors build_directory - build-darwin-x86_64 + build-darwin-universal name darwin64 diff --git a/build.sh b/build.sh index eb81ff319a4..9118cb4346a 100755 --- a/build.sh +++ b/build.sh @@ -40,7 +40,7 @@ retry_cmd() build_dir_Darwin() { - echo build-darwin-x86_64 + echo build-darwin-universal } build_dir_Linux() diff --git a/indra/cmake/OpenJPEG.cmake b/indra/cmake/OpenJPEG.cmake index d31df57689e..33e9cf48986 100644 --- a/indra/cmake/OpenJPEG.cmake +++ b/indra/cmake/OpenJPEG.cmake @@ -1,7 +1,9 @@ # -*- cmake -*- +include_guard() + include(Prebuilt) +include(Linking) -include_guard() add_library( ll::openjpeg INTERFACE IMPORTED ) use_system_binary(openjpeg) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index a315943a90f..8dc51f6efa0 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -184,9 +184,9 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "") set(CMAKE_XCODE_ATTRIBUTE_DISABLE_MANUAL_TARGET_ORDER_BUILD_WARNING YES) set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_64_TO_32_BIT_CONVERSION NO) - set(CMAKE_OSX_ARCHITECTURES "${ARCH}") - string(REPLACE "i686" "i386" CMAKE_OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}") - string(REPLACE "AMD64" "x86_64" CMAKE_OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}") + if(NOT DEFINED CMAKE_OSX_ARCHITECTURES) + set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64") + endif() endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # Default deploy grid diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index c69f4bd1f37..61e8d669083 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1028,20 +1028,6 @@ def path_optional(src, dst): ): self.path2basename(relpkgdir, libfile) - # OpenAL dylibs - if self.args['openal'] == 'ON': - for libfile in ( - "libopenal.dylib", - "libalut.dylib", - ): - dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) - - oldpath = os.path.join("@rpath", libfile) - self.run_command( - ['install_name_tool', '-change', oldpath, - '@executable_path/../Resources/%s' % libfile, - executable]) - # our apps executable_path = {} embedded_apps = [ (os.path.join("llplugin", "slplugin"), "SLPlugin.app") ] @@ -1052,13 +1038,6 @@ def path_optional(src, dst): executable_path[app] = \ self.dst_path_of(os.path.join(app, "Contents", "MacOS")) - # our apps dependencies on shared libs - # for each app, for each dylib we collected in dylibs, - # create a symlink to the real copy of the dylib. - with self.prefix(dst=os.path.join(app, "Contents", "Resources")): - for libfile in dylibs: - self.relsymlinkf(os.path.join(libfile_parent, libfile)) - # Dullahan helper apps go inside SLPlugin.app with self.prefix(dst=os.path.join( "SLPlugin.app", "Contents", "Frameworks")): From 2b44464a143c3b32ef4d3de4456b100e34ad79ef Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 28 Aug 2025 06:08:13 -0400 Subject: [PATCH 106/145] Fix up windows build error in GHA --- .github/workflows/build.yaml | 4 ++-- indra/CMakeLists.txt | 8 +++++++- indra/llcommon/llpreprocessor.h | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 4bf2af644ae..59a711267fc 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -64,7 +64,7 @@ jobs: # autobuild-package.xml. AUTOBUILD_VCS_INFO: "true" AUTOBUILD_VSVER: "170" - DEVELOPER_DIR: "/Applications/Xcode_16.1.app/Contents/Developer" + DEVELOPER_DIR: "/Applications/Xcode_16.4.app/Contents/Developer" # Ensure that Linden viewer builds engage Bugsplat. BUGSPLAT_DB: ${{ needs.setup.outputs.bugsplat_db }} build_coverity: false @@ -98,7 +98,7 @@ jobs: uses: actions/checkout@v4 with: repository: secondlife/build-variables - ref: master + ref: universal path: .build-variables - name: Checkout master-message-template diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 62f8e0ff8bf..455e7980e2e 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -10,7 +10,7 @@ ## Nicky: Ideally we want at least 3.21 for good preset support ## We're not there yet, but once done, there is a kludge in Linking.cmake # "if(${CMAKE_VERSION} VERSION_LESS "3.20.0")" that can also be removed -cmake_minimum_required(VERSION 3.16.0 FATAL_ERROR) +cmake_minimum_required(VERSION 3.16.0...4.0 FATAL_ERROR) cmake_policy(SET CMP0156 NEW) cmake_policy(SET CMP0179 NEW) @@ -35,7 +35,13 @@ if (NOT DEFINED CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 20) endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_SCAN_FOR_MODULES OFF) # This slows down build massively + set(CMAKE_OPTIMIZE_DEPENDENCIES ON) + +set(CMAKE_COLOR_DIAGNOSTICS ON) + +# Speeds up cmake generation significantly in some cases set(CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY ON) include(Variables) diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index d2a29d06b44..b2a97345487 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -181,7 +181,7 @@ #define LL_TO_STRING_HELPER(x) #x #define LL_TO_STRING(x) LL_TO_STRING_HELPER(x) -#define LL_TO_WSTRING_HELPER(x) L#x +#define LL_TO_WSTRING_HELPER(x) L## #x #define LL_TO_WSTRING(x) LL_TO_WSTRING_HELPER(x) #define LL_FILE_LINENO_MSG(msg) __FILE__ "(" LL_TO_STRING(__LINE__) ") : " msg #define LL_GLUE_IMPL(x, y) x##y From f1014eda271aec9485ad1f54c22ca331426165a5 Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 28 Aug 2025 06:19:15 -0400 Subject: [PATCH 107/145] Bump openjpeg to 2.5.3-r1 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 0bfb8b67f24..7581f719dc3 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -2087,11 +2087,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 39007a526bffffd0bde691f616491b70cf284496 + 94a72c6ddbfb23796ce913c55bc47c128542a582 hash_algorithm sha1 url - https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.2-r2/openjpeg-2.5.2.11968808495-darwin64-11968808495.tar.zst + https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.3-r1/openjpeg-2.5.3.15590356935-darwin64-15590356935.tar.zst name darwin64 @@ -2101,11 +2101,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 066e7b1ee58d5aff8efe065d598d56226c249a94 + 751172af405f4a47a3aebb37729d62229cab6c07 hash_algorithm sha1 url - https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.2-r2/openjpeg-2.5.2.11968808495-linux64-11968808495.tar.zst + https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.3-r1/openjpeg-2.5.3.15590356935-linux64-15590356935.tar.zst name linux64 @@ -2115,11 +2115,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - fe98fc9f4f3d94399c3078cad1bdcfdb37ce397b + 8aab9cf250dfee252386e1c79b5205e6d3b3e19e hash_algorithm sha1 url - https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.2-r2/openjpeg-2.5.2.11968808495-windows64-11968808495.tar.zst + https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.3-r1/openjpeg-2.5.3.15590356935-windows64-15590356935.tar.zst name windows64 @@ -2132,7 +2132,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors copyright Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium; Copyright (c) 2002-2007, Professor Benoit Macq; Copyright (c) 2001-2003, David Janssens; Copyright (c) 2002-2003, Yannick Verschueren; Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe; Copyright (c) 2005, Herve Drolon, FreeImage Team; Copyright (c) 2006-2007, Parvatha Elangovan; Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr>; Copyright (c) 2010-2011, Kaori Hagihara; Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France; Copyright (c) 2012, CS Systemes d'Information, France; version - 2.5.2.11968808495 + 2.5.3.15590356935 name openjpeg description From d010e55b88eced851543f7afd47e6c4f24964486 Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 28 Aug 2025 06:21:38 -0400 Subject: [PATCH 108/145] Tabs to spaces --- indra/llwindow/llwindowmacosx.cpp | 12 ++++++------ indra/newview/llfloaterpreference.h | 2 +- indra/newview/llfloaterpreferencesgraphicsadvanced.h | 2 +- indra/newview/pipeline.cpp | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 0e03b4e8835..030bd5ee7e3 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1495,9 +1495,9 @@ bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) convertScreenToWindow(mWindow, mouse_point); - float scale_factor = getSystemUISize(); - to->mX = mouse_point[0] * scale_factor; - to->mY = mouse_point[1] * scale_factor; + float scale_factor = getSystemUISize(); + to->mX = mouse_point[0] * scale_factor; + to->mY = mouse_point[1] * scale_factor; return true; } @@ -1509,9 +1509,9 @@ bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) if(mWindow) { float mouse_point[2]; - float scale_factor = getSystemUISize(); - mouse_point[0] = from.mX / scale_factor; - mouse_point[1] = from.mY / scale_factor; + float scale_factor = getSystemUISize(); + mouse_point[0] = from.mX / scale_factor; + mouse_point[1] = from.mY / scale_factor; convertWindowToScreen(mWindow, mouse_point); diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index fa9c421a8f0..40806c22fc0 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -237,7 +237,7 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver, std::unique_ptr< ll::prefs::SearchData > mSearchData; bool mSearchDataDirty; - boost::signals2::connection mImpostorsChangedSignal; + boost::signals2::connection mImpostorsChangedSignal; boost::signals2::connection mComplexityChangedSignal; void onUpdateFilterTerm( bool force = false ); diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.h b/indra/newview/llfloaterpreferencesgraphicsadvanced.h index a1a54f238df..6f793c13799 100644 --- a/indra/newview/llfloaterpreferencesgraphicsadvanced.h +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.h @@ -61,7 +61,7 @@ class LLFloaterPreferenceGraphicsAdvanced : public LLFloater void onBtnOK(const LLSD& userdata); void onBtnCancel(const LLSD& userdata); - boost::signals2::connection mImpostorsChangedSignal; + boost::signals2::connection mImpostorsChangedSignal; boost::signals2::connection mComplexityChangedSignal; boost::signals2::connection mComplexityModeChangedSignal; boost::signals2::connection mLODFactorChangedSignal; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 0120e1487ea..9edfbf7a887 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -7419,7 +7419,7 @@ void LLPipeline::generateGlow(LLRenderTarget* src) void LLPipeline::applyCAS(LLRenderTarget* src, LLRenderTarget* dst) { static LLCachedControl cas_sharpness(gSavedSettings, "RenderCASSharpness", 0.4f); - LL_PROFILE_GPU_ZONE("cas"); + LL_PROFILE_GPU_ZONE("cas"); if (cas_sharpness == 0.0f || !gCASProgram.isComplete()) { gPipeline.copyRenderTarget(src, dst); @@ -7464,7 +7464,7 @@ void LLPipeline::applyCAS(LLRenderTarget* src, LLRenderTarget* dst) void LLPipeline::applyFXAA(LLRenderTarget* src, LLRenderTarget* dst) { - LL_PROFILE_GPU_ZONE("FXAA"); + LL_PROFILE_GPU_ZONE("FXAA"); { llassert(!gCubeSnapshot); bool multisample = RenderFSAAType == 1 && gFXAAProgram[0].isComplete() && mFXAAMap.isComplete(); @@ -7668,7 +7668,7 @@ void LLPipeline::generateSMAABuffers(LLRenderTarget* src) void LLPipeline::applySMAA(LLRenderTarget* src, LLRenderTarget* dst) { - LL_PROFILE_GPU_ZONE("SMAA"); + LL_PROFILE_GPU_ZONE("SMAA"); llassert(!gCubeSnapshot); bool multisample = RenderFSAAType == 2 && gSMAAEdgeDetectProgram[0].isComplete() && mFXAAMap.isComplete() && mSMAABlendBuffer.isComplete(); @@ -7773,7 +7773,7 @@ void LLPipeline::combineGlow(LLRenderTarget* src, LLRenderTarget* dst) void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst) { - LL_PROFILE_GPU_ZONE("dof"); + LL_PROFILE_GPU_ZONE("dof"); { bool dof_enabled = (RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) && From 5ffcd3dc88892a651fe9a95974280efb85e18a8b Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 28 Aug 2025 14:09:03 -0400 Subject: [PATCH 109/145] Fixes for GHA build --- build.sh | 3 ++- indra/cmake/Audio.cmake | 2 +- indra/cmake/Boost.cmake | 2 +- indra/cmake/OPENAL.cmake | 4 ++++ indra/cmake/OpenJPEG.cmake | 3 +++ indra/llcommon/llprocessor.cpp | 37 ---------------------------------- 6 files changed, 11 insertions(+), 40 deletions(-) diff --git a/build.sh b/build.sh index 9118cb4346a..36e332cf42c 100755 --- a/build.sh +++ b/build.sh @@ -158,6 +158,7 @@ pre_build() if [[ "$arch" == "Darwin" ]] then + HAVOK=OFF SIGNING=("-DENABLE_SIGNING:BOOL=YES" \ "-DSIGNING_IDENTITY:STRING=Developer ID Application: Linden Research, Inc.") fi @@ -387,7 +388,7 @@ do if `cat "$build_dir/build_ok"` then case "$variant" in - Release) + Release*) if [ -r "$build_dir/autobuild-package.xml" ] then begin_section "Autobuild metadata" diff --git a/indra/cmake/Audio.cmake b/indra/cmake/Audio.cmake index 6f61b056e02..5a7a7ab0b52 100644 --- a/indra/cmake/Audio.cmake +++ b/indra/cmake/Audio.cmake @@ -33,5 +33,5 @@ find_library(VORBISFILE_LIBRARY libvorbisfile.a PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) -target_link_libraries(ll::vorbis INTERFACE ${OGG_LIBRARY} ${VORBISENC_LIBRARY} ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY}) +target_link_libraries(ll::vorbis INTERFACE ${VORBISENC_LIBRARY} ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY} ) diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 518e6785859..7b3882c936e 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -65,8 +65,8 @@ find_library(BOOST_URL_LIBRARY PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) target_link_libraries(ll::boost INTERFACE - ${BOOST_CONTEXT_LIBRARY} ${BOOST_FIBER_LIBRARY} + ${BOOST_CONTEXT_LIBRARY} ${BOOST_FILESYSTEM_LIBRARY} ${BOOST_PROGRAMOPTIONS_LIBRARY} ${BOOST_REGEX_LIBRARY} diff --git a/indra/cmake/OPENAL.cmake b/indra/cmake/OPENAL.cmake index 2566a081895..ab1604aa22a 100644 --- a/indra/cmake/OPENAL.cmake +++ b/indra/cmake/OPENAL.cmake @@ -26,11 +26,15 @@ if (USE_OPENAL) NAMES OpenAL32 openal + libopenal.dylib + libopenal.so PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) find_library(ALUT_LIBRARY NAMES alut + libalut.dylib + libalut.so PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) target_link_libraries(ll::openal INTERFACE ${OPENAL_LIBRARY} ${ALUT_LIBRARY}) diff --git a/indra/cmake/OpenJPEG.cmake b/indra/cmake/OpenJPEG.cmake index 33e9cf48986..95e71fd78e8 100644 --- a/indra/cmake/OpenJPEG.cmake +++ b/indra/cmake/OpenJPEG.cmake @@ -12,6 +12,9 @@ use_prebuilt_binary(openjpeg) find_library(OPENJPEG_LIBRARY NAMES openjp2 + openjp2.lib + libopenjp2.a + libopenjp2.so PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) target_link_libraries(ll::openjpeg INTERFACE ${OPENJPEG_LIBRARY}) diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index a6ecad2cf70..718f4713213 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -640,43 +640,6 @@ class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl { getCPUIDInfo(); uint64_t frequency = getSysctlInt64("hw.cpufrequency"); - if(frequency == 0) // Attempt to query IO Services for pcore frequency - { - CFMutableDictionaryRef arm_io_matching = IOServiceMatching("AppleARMIODevice"); - io_iterator_t iter; - kern_return_t ret = IOServiceGetMatchingServices(kIOMasterPortDefault, arm_io_matching, &iter); - if(ret == KERN_SUCCESS) - { - io_object_t obj; - while ((obj = IOIteratorNext(iter))) - { - io_name_t obj_class; - ret = IOObjectGetClass(obj, obj_class); - if(ret == KERN_SUCCESS) - { - io_name_t obj_name; - ret = IORegistryEntryGetName(obj, obj_name); - if(ret == KERN_SUCCESS) - { - if (strncmp(obj_name, "pmgr", sizeof(obj_name)) == 0) - { - CFTypeRef cfData = IORegistryEntryCreateCFProperty(obj, CFSTR("voltage-states5-sram"), kCFAllocatorDefault, 0); // pcore frequency - if(cfData) - { - CFIndex size = CFDataGetLength((CFDataRef)cfData); - std::vector databuf(size); - CFDataGetBytes((CFDataRef)cfData, CFRangeMake(0, size), databuf.data()); - - frequency = 0x00000000FFFFFFFF & ((databuf[size-5] << 24) | (databuf[size-6] << 16) | (databuf[size-7] << 8) | (databuf[size-8])); - CFRelease(cfData); - } - break; - } - } - } - } - } - } if (frequency == 0) // fallback to clockrate and tbfrequency { frequency = getSysctlClockrate() * getSysctlInt64("hw.tbfrequency"); From e23aa060494ea1ae8f01033177ec10c333f01b30 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 29 Aug 2025 00:02:04 +0300 Subject: [PATCH 110/145] #4604 Reduce draw distance when low on RAM --- indra/newview/llviewermessage.cpp | 23 ++++++++++---- indra/newview/llviewertexture.cpp | 51 +++++++++++++++++++++++++------ indra/newview/llviewertexture.h | 3 ++ indra/newview/llvocache.cpp | 13 ++++++-- 4 files changed, 72 insertions(+), 18 deletions(-) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 7d39cc60597..d0e6af799c4 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3364,6 +3364,17 @@ void send_agent_update(bool force_send, bool send_reliable) msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis()); static F32 last_draw_disatance_step = 1024; + F32 memory_limited_draw_distance = gAgentCamera.mDrawDistance; + + if (LLViewerTexture::sDesiredDiscardBias > 2.f && LLViewerTexture::isSystemMemoryLow()) + { + // If we are low on memory, reduce requested draw distance + // Discard's bias is clamped to 4 so we need to check 2 to 4 range + // Factor is intended to go from 1.0 to 2.0 + F32 factor = 1.f + (LLViewerTexture::sDesiredDiscardBias - 2.f) / 2.f; + memory_limited_draw_distance = llmax(gAgentCamera.mDrawDistance / factor, gAgentCamera.mDrawDistance / 2.f); + } + if (tp_state == LLAgent::TELEPORT_ARRIVING || LLStartUp::getStartupState() < STATE_MISC) { // Inform interest list, prioritize closer area. @@ -3372,25 +3383,25 @@ void send_agent_update(bool force_send, bool send_reliable) // closer ones. // Todo: revise and remove once server gets distance sorting. last_draw_disatance_step = llmax((F32)(gAgentCamera.mDrawDistance / 2.f), 50.f); + last_draw_disatance_step = llmin(last_draw_disatance_step, memory_limited_draw_distance); msg->addF32Fast(_PREHASH_Far, last_draw_disatance_step); } - else if (last_draw_disatance_step < gAgentCamera.mDrawDistance) + else if (last_draw_disatance_step < memory_limited_draw_distance) { static LLFrameTimer last_step_time; if (last_step_time.getElapsedTimeF32() > 1.f) { // gradually increase draw distance - // Idealy this should be not per second, but based on how loaded - // mesh thread is, but hopefully this is temporary. last_step_time.reset(); - F32 step = gAgentCamera.mDrawDistance * 0.1f; - last_draw_disatance_step = llmin(last_draw_disatance_step + step, gAgentCamera.mDrawDistance); + F32 step = memory_limited_draw_distance * 0.1f; + last_draw_disatance_step = llmin(last_draw_disatance_step + step, memory_limited_draw_distance); } msg->addF32Fast(_PREHASH_Far, last_draw_disatance_step); } else { - msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance); + last_draw_disatance_step = memory_limited_draw_distance; + msg->addF32Fast(_PREHASH_Far, memory_limited_draw_distance); } msg->addU32Fast(_PREHASH_ControlFlags, control_flags); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 52939dbbae9..7a25fb03a57 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -527,8 +527,16 @@ void LLViewerTexture::updateClass() if (is_low && !was_low) { - // slam to 1.5 bias the moment we hit low memory (discards off screen textures immediately) - sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.5f); + if (is_sys_low) + { + // Not having system memory is more serious, so discard harder + sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.5f * getSystemMemoryBudgetFactor()); + } + else + { + // Slam to 1.5 bias the moment we hit low memory (discards off screen textures immediately) + sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.5f); + } if (is_sys_low || over_pct > 2.f) { // if we're low on system memory, emergency purge off screen textures to avoid a death spiral @@ -559,8 +567,13 @@ void LLViewerTexture::updateClass() sEvaluationTimer.reset(); // lower discard bias over time when at least 10% of budget is free - const F32 FREE_PERCENTAGE_TRESHOLD = -0.1f; - if (sDesiredDiscardBias > 1.f && over_pct < FREE_PERCENTAGE_TRESHOLD) + constexpr F32 FREE_PERCENTAGE_TRESHOLD = -0.1f; + constexpr U32 FREE_SYS_MEM_TRESHOLD = 100; + static LLCachedControl min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512); + const S32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory() + FREE_SYS_MEM_TRESHOLD); + if (sDesiredDiscardBias > 1.f + && over_pct < FREE_PERCENTAGE_TRESHOLD + && getFreeSystemMemory() > MIN_FREE_MAIN_MEMORY) { static LLCachedControl high_mem_discard_decrement(gSavedSettings, "RenderHighMemMinDiscardDecrement", .1f); @@ -627,24 +640,42 @@ void LLViewerTexture::updateClass() } //static -bool LLViewerTexture::isSystemMemoryLow() +U32Megabytes LLViewerTexture::getFreeSystemMemory() { static LLFrameTimer timer; static U32Megabytes physical_res = U32Megabytes(U32_MAX); - static LLCachedControl min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512); - const U32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory); - if (timer.getElapsedTimeF32() < MEMORY_CHECK_WAIT_TIME) //call this once per second. { - return physical_res < MIN_FREE_MAIN_MEMORY; + return physical_res; } timer.reset(); LLMemory::updateMemoryInfo(); physical_res = LLMemory::getAvailableMemKB(); - return physical_res < MIN_FREE_MAIN_MEMORY; + return physical_res; +} + +//static +bool LLViewerTexture::isSystemMemoryLow() +{ + static LLCachedControl min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512); + const U32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory); + return getFreeSystemMemory() < MIN_FREE_MAIN_MEMORY; +} + +F32 LLViewerTexture::getSystemMemoryBudgetFactor() +{ + static LLCachedControl min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512); + const S32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory); + S32 free_budget = (S32Megabytes)getFreeSystemMemory() - MIN_FREE_MAIN_MEMORY; + if (free_budget < 0) + { + // Result should range from 1 (0 free budget) to 2 (-512 free budget) + return 1.f - free_budget / MIN_FREE_MAIN_MEMORY; + } + return 1.f; } //end of static functions diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index f9311d85cbf..d32c302d8e1 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -115,6 +115,7 @@ class LLViewerTexture : public LLGLTexture static void initClass(); static void updateClass(); static bool isSystemMemoryLow(); + static F32 getSystemMemoryBudgetFactor(); LLViewerTexture(bool usemipmaps = true); LLViewerTexture(const LLUUID& id, bool usemipmaps) ; @@ -189,6 +190,8 @@ class LLViewerTexture : public LLGLTexture friend class LLBumpImageList; friend class LLUIImageList; + static U32Megabytes getFreeSystemMemory(); + protected: friend class LLViewerTextureList; LLUUID mID; diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 501828eee8e..ac73c2def65 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -486,14 +486,23 @@ void LLVOCacheEntry::updateDebugSettings() //min radius: all objects within this radius remain loaded in memory static LLCachedControl min_radius(gSavedSettings,"SceneLoadMinRadius"); static const F32 MIN_RADIUS = 1.0f; - const F32 draw_radius = gAgentCamera.mDrawDistance; + + F32 draw_radius = gAgentCamera.mDrawDistance; + if (LLViewerTexture::sDesiredDiscardBias > 2.f && LLViewerTexture::isSystemMemoryLow()) + { + // Discard's bias maximum is 4 so we need to check 2 to 4 range + // Factor is intended to go from 1.0 to 2.0 + F32 factor = 1.f + (LLViewerTexture::sDesiredDiscardBias - 2.f) / 2.f; + // For safety cap reduction at 50%, we don't want to go below half of draw distance + draw_radius = llmax(draw_radius / factor, draw_radius / 2.f); + } const F32 clamped_min_radius = llclamp((F32) min_radius, MIN_RADIUS, draw_radius); // [1, mDrawDistance] sNearRadius = MIN_RADIUS + ((clamped_min_radius - MIN_RADIUS) * adjust_factor); // a percentage of draw distance beyond which all objects outside of view frustum will be unloaded, regardless of pixel threshold static LLCachedControl rear_max_radius_frac(gSavedSettings,"SceneLoadRearMaxRadiusFraction"); const F32 min_radius_plus_one = sNearRadius + 1.f; - const F32 max_radius = rear_max_radius_frac * gAgentCamera.mDrawDistance; + const F32 max_radius = rear_max_radius_frac * draw_radius; const F32 clamped_max_radius = llclamp(max_radius, min_radius_plus_one, draw_radius); // [sNearRadius, mDrawDistance] sRearFarRadius = min_radius_plus_one + ((clamped_max_radius - min_radius_plus_one) * adjust_factor); From 479fee984a595cab4fad0aae9157c5e168da692f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 29 Aug 2025 00:03:07 +0300 Subject: [PATCH 111/145] #4604 Warn user off high settings when on low-RAM hardware --- indra/newview/llfloaterpreference.cpp | 28 +++++++++++++++++++ indra/newview/llfloaterpreference.h | 1 + .../skins/default/xui/en/notifications.xml | 11 ++++++++ 3 files changed, 40 insertions(+) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index b74736a39d5..291f22d78fa 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -758,6 +758,7 @@ void LLFloaterPreference::onOpen(const LLSD& key) // Forget previous language changes. mLanguageChanged = false; + mLastQualityLevel = gSavedSettings.getU32("RenderQualityPerformance"); // Display selected maturity icons. onChangeMaturity(); @@ -1327,6 +1328,33 @@ void LLFloaterPreference::onCommitWindowedMode() void LLFloaterPreference::onChangeQuality(const LLSD& data) { U32 level = (U32)(data.asReal()); + constexpr U32 LVL_HIGH = 4; + if (level >= LVL_HIGH && mLastQualityLevel < level) + { + constexpr U32 LOW_MEM_THRESHOLD = 4097; + U32 total_mem = (U32Megabytes)LLMemory::getMaxMemKB(); + if (total_mem < LOW_MEM_THRESHOLD) + { + LLSD args; + args["TOTAL_MEM"] = LLSD::Integer(total_mem); + LLNotificationsUtil::add("PreferenceQualityWithLowMemory", args, LLSD(), [this](const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + // If cancel pressed + if (option == 1) + { + constexpr U32 LVL_MED_PLUS = 3; + gSavedSettings.setU32("RenderQualityPerformance", LVL_MED_PLUS); + mLastQualityLevel = LVL_MED_PLUS; + LLFeatureManager::getInstance()->setGraphicsLevel(LVL_MED_PLUS, true); + refreshEnabledGraphics(); + refresh(); + } + } + ); + } + } + mLastQualityLevel = level; LLFeatureManager::getInstance()->setGraphicsLevel(level, true); refreshEnabledGraphics(); refresh(); diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index fa9c421a8f0..61ac0a4d770 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -218,6 +218,7 @@ class LLFloaterPreference : public LLFloater, public LLAvatarPropertiesObserver, bool mGotPersonalInfo; bool mLanguageChanged; bool mAvatarDataInitialized; + U32 mLastQualityLevel = 0; std::string mPriorInstantMessageLogPath; bool mOriginalHideOnlineStatus; diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index b182a241d8a..7fc96af55d7 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -12145,6 +12145,17 @@ Cannot create large prims that intersect other residents. Please re-try when ot yestext="OK"/> + +Your system has [TOTAL_MEM]MB of memory, which might not be enough to run viewer at higher settings and might result in issues. + + + Date: Fri, 29 Aug 2025 20:33:32 +0300 Subject: [PATCH 112/145] #4598 Fix variables being inited before settings are ready --- indra/newview/llreflectionmapmanager.cpp | 1 - indra/newview/pipeline.cpp | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index f24bb892dc1..663d8626b7a 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -145,7 +145,6 @@ static void touch_default_probe(LLReflectionMap* probe) LLReflectionMapManager::LLReflectionMapManager() { mDynamicProbeCount = LL_MAX_REFLECTION_PROBE_COUNT; - refreshSettings(); initCubeFree(); } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 493fcd5d45b..209b06fd857 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -426,6 +426,8 @@ void LLPipeline::init() sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); + mReflectionMapManager.refreshSettings(); + mInitialized = true; stop_glerror(); From 5d50a660bc6ac480b1f92db47bcb3974104bf4d1 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 27 Aug 2025 22:03:32 +0300 Subject: [PATCH 113/145] #4588 Unable to direct silent installation --- .../installers/windows/installer_template.nsi | 86 ++++++++++++++++++- indra/newview/llstartup.cpp | 1 + 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 77f24ac6a68..0e366980185 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -163,6 +163,74 @@ Var DO_UNINSTALL_V2 # If non-null, path to a previous Viewer 2 installation !include 'LogicLib.nsh' # for value comparison !include "x64.nsh" # for 64bit detection +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Substring function +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +!define StrStr "!insertmacro StrStr" + +!macro StrStr ResultVar String SubString + Push `${String}` + Push `${SubString}` + Call StrStr + Pop `${ResultVar}` +!macroend + +Function StrStr + +# After this point: +# ------------------------------------------ +# $R0 = SubString (input) +# $R1 = String (input) +# $R2 = SubStringLen (temp) +# $R3 = StrLen (temp) +# $R4 = StartCharPos (temp) +# $R5 = TempStr (temp) +# function from nsis.sourceforge.io/StrStr + + ;Get input from user + Exch $R0 + Exch + Exch $R1 + Push $R2 + Push $R3 + Push $R4 + Push $R5 + + ;Get "String" and "SubString" length + StrLen $R2 $R0 + StrLen $R3 $R1 + ;Start "StartCharPos" counter + StrCpy $R4 0 + + ;Loop until "SubString" is found or "String" reaches its end + ${Do} + ;Remove everything before and after the searched part ("TempStr") + StrCpy $R5 $R1 $R2 $R4 + + ;Compare "TempStr" with "SubString" + ${IfThen} $R5 == $R0 ${|} ${ExitDo} ${|} + ;If not "SubString", this could be "String"'s end + ${IfThen} $R4 >= $R3 ${|} ${ExitDo} ${|} + ;If not, continue the loop + IntOp $R4 $R4 + 1 + ${Loop} + +# After this point: +# ------------------------------------------ +# $R0 = ResultVar (output) + + ;Remove part before "SubString" on "String" (if there has one) + StrCpy $R0 $R1 `` $R4 + + ;Return output to user + Pop $R5 + Pop $R4 + Pop $R3 + Pop $R2 + Pop $R1 + Exch $R0 +FunctionEnd + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Pre-directory page callback ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -190,15 +258,31 @@ Function .onInit # However, SL-10506 complains about the resulting behavior, so the logic below # is adapted from before we introduced MultiUser.nsh. +# Check if user specified /D= on the command line +System::Call 'kernel32::GetCommandLine()t .r0' +Push $0 +Push " /D=" +Call StrStr +Pop $1 +${If} $1 != "" + # /D= was specified, extract the path + # spaces are allowed in path after /D=, it's expected to be the last parameter + StrLen $2 $1 + StrCpy $INSTDIR $1 $2 4 # Skip over " /D=" + Goto after_instdir +${EndIf} + # if $0 is empty, this is the first time for this viewer name ReadRegStr $0 SHELL_CONTEXT "${INSTNAME_KEY}" "" # viewer with this name was installed before ${If} $0 != "" - # use the value we got from registry as install location + # use the value we got from registry as install location StrCpy $INSTDIR $0 ${EndIf} +after_instdir: + Call CheckCPUFlags # Make sure we have SSE2 support Call CheckWindowsVersion # Don't install On unsupported systems Push $0 diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index ba7437798a9..5df7eca5f5d 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -397,6 +397,7 @@ bool idle_startup() LL_WARNS_ONCE() << "gViewerWindow is not initialized" << LL_ENDL; return false; // No world yet } + LL_PROFILE_ZONE_SCOPED; const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay"); static LLTimer timeout; From 9959f51741dc6b2eb04485b3443334e1e2e30d19 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 1 Sep 2025 22:37:46 +0300 Subject: [PATCH 114/145] #4619 Don't crash on LLHUDEffect::render LLHUDEffectResetSkeleton needs to override LLHUDEffect::render to not cause an LL_ERRS if it stays alive for too long. --- indra/newview/llhudeffectresetskeleton.cpp | 9 +++++++++ indra/newview/llhudeffectresetskeleton.h | 13 +++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/indra/newview/llhudeffectresetskeleton.cpp b/indra/newview/llhudeffectresetskeleton.cpp index 31065a3e762..2bb5696f593 100644 --- a/indra/newview/llhudeffectresetskeleton.cpp +++ b/indra/newview/llhudeffectresetskeleton.cpp @@ -53,6 +53,15 @@ LLHUDEffectResetSkeleton::~LLHUDEffectResetSkeleton() { } +//----------------------------------------------------------------------------- +// packData() +//----------------------------------------------------------------------------- +void LLHUDEffectResetSkeleton::render() +{ + // HUDEffectResetSkeleton is a fake effect meant to reset skeleton only. + // Just wait for an update() call to do its work and then die. +} + //----------------------------------------------------------------------------- // packData() //----------------------------------------------------------------------------- diff --git a/indra/newview/llhudeffectresetskeleton.h b/indra/newview/llhudeffectresetskeleton.h index 39a61370548..c89516d7fcd 100644 --- a/indra/newview/llhudeffectresetskeleton.h +++ b/indra/newview/llhudeffectresetskeleton.h @@ -38,20 +38,21 @@ class LLHUDEffectResetSkeleton final : public LLHUDEffect public: friend class LLHUDObject; - /*virtual*/ void markDead(); - /*virtual*/ void setSourceObject(LLViewerObject* objectp); + /*virtual*/ void markDead() override; + /*virtual*/ void setSourceObject(LLViewerObject* objectp) override; - void setTargetObject(LLViewerObject *objp); + void setTargetObject(LLViewerObject *objp) override; void setResetAnimations(bool enable){ mResetAnimations = enable; }; protected: LLHUDEffectResetSkeleton(const U8 type); ~LLHUDEffectResetSkeleton(); - /*virtual*/ void packData(LLMessageSystem *mesgsys); - /*virtual*/ void unpackData(LLMessageSystem *mesgsys, S32 blocknum); + void render() override; + void packData(LLMessageSystem *mesgsys) override; + void unpackData(LLMessageSystem *mesgsys, S32 blocknum) override; - void update(); + void update() override; private: bool mResetAnimations; }; From e5b7e8a9a822e69777e406d5be8239155a47155b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 1 Sep 2025 22:56:58 +0300 Subject: [PATCH 115/145] #4621 Crash at LLMeshRepoThread::run(1060) Fix a missed mutex --- indra/newview/llmeshrepository.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 997fc28333a..8d5f94cdbb0 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2310,6 +2310,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes } if (request_skin) { + LLMutexLock lock(mMutex); mSkinRequests.push_back(UUIDBasedRequest(mesh_id)); } } From 0fe641a3f20997c970112df7d188510993733338 Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 27 Aug 2025 22:36:55 -0400 Subject: [PATCH 116/145] Changes to support dullahan 1.21 undo/redo/delete/select all edit handlers --- indra/llplugin/llpluginclassmedia.cpp | 50 ++++++++++++ indra/llplugin/llpluginclassmedia.h | 18 +++++ indra/media_plugins/cef/media_plugin_cef.cpp | 59 +++++++++++++- indra/newview/llmediactrl.cpp | 10 ++- indra/newview/llmediactrl.h | 1 + indra/newview/llviewermedia.cpp | 80 +++++++++++++++++++ indra/newview/llviewermedia.h | 12 +++ .../skins/default/xui/en/menu_media_ctrl.xml | 8 ++ 8 files changed, 236 insertions(+), 2 deletions(-) diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 8a356da93a9..77a4b08af55 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -132,9 +132,13 @@ void LLPluginClassMedia::reset() mLastMouseY = 0; mStatus = LLPluginClassMediaOwner::MEDIA_NONE; mSleepTime = 1.0f / 100.0f; + mCanUndo = false; + mCanRedo = false; mCanCut = false; mCanCopy = false; mCanPaste = false; + mCanDoDelete = false; + mCanSelectAll = false; mMediaName.clear(); mMediaDescription.clear(); mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f); @@ -907,6 +911,18 @@ void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, sendMessage(message); } +void LLPluginClassMedia::undo() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_undo"); + sendMessage(message); +} + +void LLPluginClassMedia::redo() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_redo"); + sendMessage(message); +} + void LLPluginClassMedia::cut() { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); @@ -925,6 +941,24 @@ void LLPluginClassMedia::paste() sendMessage(message); } +void LLPluginClassMedia::doDelete() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_delete"); + sendMessage(message); +} + +void LLPluginClassMedia::selectAll() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_select_all"); + sendMessage(message); +} + +void LLPluginClassMedia::showPageSource() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_show_source"); + sendMessage(message); +} + void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path_cache, const std::string &username, const std::string &user_data_path_cef_log) @@ -1178,6 +1212,14 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) } else if(message_name == "edit_state") { + if(message.hasValue("undo")) + { + mCanUndo = message.getValueBoolean("undo"); + } + if(message.hasValue("redo")) + { + mCanRedo = message.getValueBoolean("redo"); + } if(message.hasValue("cut")) { mCanCut = message.getValueBoolean("cut"); @@ -1190,6 +1232,14 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { mCanPaste = message.getValueBoolean("paste"); } + if (message.hasValue("delete")) + { + mCanDoDelete = message.getValueBoolean("delete"); + } + if (message.hasValue("select_all")) + { + mCanSelectAll = message.getValueBoolean("select_all"); + } } else if(message_name == "name_text") { diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index d74b790d8f7..292d9344195 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -201,6 +201,12 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; } + void undo(); + bool canUndo() const { return mCanUndo; }; + + void redo(); + bool canRedo() const { return mCanRedo; }; + void cut(); bool canCut() const { return mCanCut; }; @@ -210,6 +216,14 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner void paste(); bool canPaste() const { return mCanPaste; }; + void doDelete(); + bool canDoDelete() const { return mCanDoDelete; }; + + void selectAll(); + bool canSelectAll() const { return mCanSelectAll; }; + + void showPageSource(); + // These can be called before init(), and they will be queued and sent before the media init message. void setUserDataPath(const std::string &user_data_path_cache, const std::string &username, const std::string &user_data_path_cef_log); void setLanguageCode(const std::string &language_code); @@ -419,9 +433,13 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner F64 mSleepTime; + bool mCanUndo; + bool mCanRedo; bool mCanCut; bool mCanCopy; bool mCanPaste; + bool mCanDoDelete; + bool mCanSelectAll; std::string mMediaName; std::string mMediaDescription; diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 52df4a96859..caf804f915d 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -106,9 +106,13 @@ class MediaPluginCEF : std::string mAuthUsername; std::string mAuthPassword; bool mAuthOK; + bool mCanUndo; + bool mCanRedo; bool mCanCut; bool mCanCopy; bool mCanPaste; + bool mCanDelete; + bool mCanSelectAll; std::string mRootCachePath; std::string mCefLogFile; bool mCefLogVerbose; @@ -144,9 +148,13 @@ MediaPluginBase(host_send_func, host_user_data) mAuthUsername = ""; mAuthPassword = ""; mAuthOK = false; + mCanUndo = false; + mCanRedo = false; mCanCut = false; mCanCopy = false; mCanPaste = false; + mCanDelete = false; + mCanSelectAll = false; mCefLogFile = ""; mCefLogVerbose = false; mPickedFiles.clear(); @@ -940,6 +948,14 @@ void MediaPluginCEF::receiveMessage(const char* message_string) { authResponse(message_in); } + if (message_name == "edit_undo") + { + mCEFLib->editUndo(); + } + if (message_name == "edit_redo") + { + mCEFLib->editRedo(); + } if (message_name == "edit_cut") { mCEFLib->editCut(); @@ -952,6 +968,18 @@ void MediaPluginCEF::receiveMessage(const char* message_string) { mCEFLib->editPaste(); } + if (message_name == "edit_delete") + { + mCEFLib->editDelete(); + } + if (message_name == "edit_select_all") + { + mCEFLib->editSelectAll(); + } + if (message_name == "edit_show_source") + { + mCEFLib->viewSource(); + } } else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) { @@ -1103,14 +1131,31 @@ void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD // void MediaPluginCEF::checkEditState() { + bool can_undo = mCEFLib->editCanUndo(); + bool can_redo = mCEFLib->editCanRedo(); bool can_cut = mCEFLib->editCanCut(); bool can_copy = mCEFLib->editCanCopy(); bool can_paste = mCEFLib->editCanPaste(); + bool can_delete = mCEFLib->editCanDelete(); + bool can_select_all = mCEFLib->editCanSelectAll(); - if ((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste)) + if ((can_undo != mCanUndo) || (can_redo != mCanRedo) || (can_cut != mCanCut) || (can_copy != mCanCopy) + || (can_paste != mCanPaste) || (can_delete != mCanDelete) || (can_select_all != mCanSelectAll)) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state"); + if (can_undo != mCanUndo) + { + mCanUndo = can_undo; + message.setValueBoolean("undo", can_undo); + } + + if (can_redo != mCanRedo) + { + mCanRedo = can_redo; + message.setValueBoolean("redo", can_redo); + } + if (can_cut != mCanCut) { mCanCut = can_cut; @@ -1129,6 +1174,18 @@ void MediaPluginCEF::checkEditState() message.setValueBoolean("paste", can_paste); } + if (can_delete != mCanDelete) + { + mCanDelete = can_delete; + message.setValueBoolean("delete", can_delete); + } + + if (can_select_all != mCanSelectAll) + { + mCanSelectAll = can_select_all; + message.setValueBoolean("select_all", can_select_all); + } + sendMessage(message); } } diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 202008f7f93..c7b60b2fd56 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -347,6 +347,7 @@ bool LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask ) { LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); + registar.add("Open.ShowSource", boost::bind(&LLMediaCtrl::onShowSource, this)); // stinson 05/05/2014 : use this as the parent of the context menu if the static menu // container has yet to be created @@ -364,8 +365,9 @@ bool LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask ) { // hide/show debugging options bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging"); + menu->setItemVisible("debug_separator", media_plugin_debugging_enabled); menu->setItemVisible("open_webinspector", media_plugin_debugging_enabled ); - menu->setItemVisible("debug_separator", media_plugin_debugging_enabled ); + menu->setItemVisible("show_page_source", media_plugin_debugging_enabled); menu->show(x, y); LLMenuGL::showPopup(this, menu, x, y); @@ -444,6 +446,12 @@ void LLMediaCtrl::onOpenWebInspector() mMediaSource->getMediaPlugin()->showWebInspector( true ); } +void LLMediaCtrl::onShowSource() +{ + if (mMediaSource && mMediaSource->hasMedia()) + mMediaSource->getMediaPlugin()->showPageSource(); +} + //////////////////////////////////////////////////////////////////////////////// // bool LLMediaCtrl::handleKeyHere( KEY key, MASK mask ) diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 9f9564af46c..a644ef30719 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -171,6 +171,7 @@ class LLMediaCtrl : // right click debugging item void onOpenWebInspector(); + void onShowSource(); LLUUID getTextureID() {return mMediaTextureID;} diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index c6bc252efd2..89861d74bc5 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -3508,6 +3508,46 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla } } +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::undo() +{ + if (mMediaSource) + mMediaSource->undo(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +bool +LLViewerMediaImpl::canUndo() const +{ + if (mMediaSource) + return mMediaSource->canUndo(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::redo() +{ + if (mMediaSource) + mMediaSource->redo(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +bool +LLViewerMediaImpl::canRedo() const +{ + if (mMediaSource) + return mMediaSource->canRedo(); + else + return FALSE; +} + //////////////////////////////////////////////////////////////////////////////// // virtual void @@ -3568,6 +3608,46 @@ LLViewerMediaImpl::canPaste() const return false; } +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::doDelete() +{ + if (mMediaSource) + mMediaSource->doDelete(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +bool +LLViewerMediaImpl::canDoDelete() const +{ + if (mMediaSource) + return mMediaSource->canDoDelete(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::selectAll() +{ + if (mMediaSource) + mMediaSource->selectAll(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +bool +LLViewerMediaImpl::canSelectAll() const +{ + if (mMediaSource) + return mMediaSource->canSelectAll(); + else + return FALSE; +} + void LLViewerMediaImpl::setUpdated(bool updated) { mIsUpdated = updated ; diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 5753615a432..c17cf598159 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -341,6 +341,12 @@ class LLViewerMediaImpl /*virtual*/ void handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent); // LLEditMenuHandler overrides + /*virtual*/ void undo(); + /*virtual*/ bool canUndo() const; + + /*virtual*/ void redo(); + /*virtual*/ bool canRedo() const; + /*virtual*/ void cut(); /*virtual*/ bool canCut() const; @@ -350,6 +356,12 @@ class LLViewerMediaImpl /*virtual*/ void paste(); /*virtual*/ bool canPaste() const; + /*virtual*/ void doDelete(); + /*virtual*/ bool canDoDelete() const; + + /*virtual*/ void selectAll(); + /*virtual*/ bool canSelectAll() const; + void addObject(LLVOVolume* obj) ; void removeObject(LLVOVolume* obj) ; const std::list< LLVOVolume* >* getObjectList() const ; diff --git a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml index f9864637a00..e687ae93e8d 100644 --- a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml +++ b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml @@ -40,4 +40,12 @@ + + + From 012c0705bd30510167c3cb86343cccb72d23bf71 Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 27 Aug 2025 23:05:40 -0400 Subject: [PATCH 117/145] MacOS companion changes for dullahan 1.21 including package structure and linkage fixes --- indra/cmake/00-Common.cmake | 3 + indra/cmake/CEFPlugin.cmake | 1 - indra/cmake/PluginAPI.cmake | 4 + indra/llfilesystem/lldir_mac.cpp | 2 +- indra/llplugin/CMakeLists.txt | 2 +- indra/llplugin/llpluginclassmedia.h | 7 +- indra/llplugin/slplugin/CMakeLists.txt | 28 ++-- indra/media_plugins/base/CMakeLists.txt | 2 +- indra/media_plugins/cef/CMakeLists.txt | 10 +- indra/media_plugins/example/CMakeLists.txt | 2 +- indra/media_plugins/libvlc/CMakeLists.txt | 2 +- .../libvlc/media_plugin_libvlc.cpp | 2 +- indra/newview/CMakeLists.txt | 6 +- indra/newview/viewer_manifest.py | 123 +++--------------- 14 files changed, 52 insertions(+), 142 deletions(-) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index c895f423624..5943e0b5734 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -162,6 +162,9 @@ endif (LINUX) if (DARWIN) + # Use rpath loading on macos + set(CMAKE_MACOSX_RPATH TRUE) + # Warnings should be fatal -- thanks, Nicky Perian, for spotting reversed default set(CLANG_DISABLE_FATAL_WARNINGS OFF) set(CMAKE_CXX_LINK_FLAGS "-Wl,-headerpad_max_install_names,-search_paths_first") diff --git a/indra/cmake/CEFPlugin.cmake b/indra/cmake/CEFPlugin.cmake index 9b77becf29f..e27929fa088 100644 --- a/indra/cmake/CEFPlugin.cmake +++ b/indra/cmake/CEFPlugin.cmake @@ -29,7 +29,6 @@ elseif (DARWIN) ${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a ${ARCH_PREBUILT_DIRS_RELEASE}/libdullahan.a ${APPKIT_LIBRARY} - "-F ${CEF_LIBRARY}" ) elseif (LINUX) diff --git a/indra/cmake/PluginAPI.cmake b/indra/cmake/PluginAPI.cmake index 114415e514b..a2bf13db2c9 100644 --- a/indra/cmake/PluginAPI.cmake +++ b/indra/cmake/PluginAPI.cmake @@ -1,5 +1,7 @@ # -*- cmake -*- +include(OpenGL) + add_library( ll::pluginlibraries INTERFACE IMPORTED ) if (WINDOWS) @@ -13,4 +15,6 @@ if (WINDOWS) ) endif (WINDOWS) +target_link_libraries( ll::pluginlibraries INTERFACE OpenGL::GL) +target_include_directories( ll::pluginlibraries INTERFACE ${CMAKE_SOURCE_DIR}/llimage ${CMAKE_SOURCE_DIR}/llrender) diff --git a/indra/llfilesystem/lldir_mac.cpp b/indra/llfilesystem/lldir_mac.cpp index b9be75c528f..2db1b6ec5d4 100644 --- a/indra/llfilesystem/lldir_mac.cpp +++ b/indra/llfilesystem/lldir_mac.cpp @@ -149,7 +149,7 @@ LLDir_Mac::LLDir_Mac() mWorkingDir = getCurPath(); - mLLPluginDir = mAppRODataDir + mDirDelimiter + "llplugin"; + mLLPluginDir = mAppRODataDir + mDirDelimiter + "SLPlugin.app" + mDirDelimiter + "Contents" + mDirDelimiter + "Frameworks"; } } diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt index 14a69afe6eb..f7f8c08adb4 100644 --- a/indra/llplugin/CMakeLists.txt +++ b/indra/llplugin/CMakeLists.txt @@ -43,6 +43,6 @@ list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES}) add_library (llplugin ${llplugin_SOURCE_FILES}) target_include_directories( llplugin INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries( llplugin llcommon llmath llrender llmessage ) +target_link_libraries( llplugin llcommon llmath llmessage llxml ) add_subdirectory(slplugin) diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 292d9344195..71522bcd7d5 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -29,7 +29,6 @@ #ifndef LL_LLPLUGINCLASSMEDIA_H #define LL_LLPLUGINCLASSMEDIA_H -#include "llgltypes.h" #include "llpluginprocessparent.h" #include "llrect.h" #include "llpluginclassmediaowner.h" @@ -365,9 +364,9 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true S32 mRequestedTextureDepth; - LLGLenum mRequestedTextureInternalFormat; - LLGLenum mRequestedTextureFormat; - LLGLenum mRequestedTextureType; + U32 mRequestedTextureInternalFormat; + U32 mRequestedTextureFormat; + U32 mRequestedTextureType; bool mRequestedTextureSwapBytes; bool mRequestedTextureCoordsOpenGL; diff --git a/indra/llplugin/slplugin/CMakeLists.txt b/indra/llplugin/slplugin/CMakeLists.txt index 0ea6495eaca..e639e522afb 100644 --- a/indra/llplugin/slplugin/CMakeLists.txt +++ b/indra/llplugin/slplugin/CMakeLists.txt @@ -30,18 +30,6 @@ add_executable(SLPlugin ${SLPlugin_SOURCE_FILES} ) -if (WINDOWS) -set_target_properties(SLPlugin - PROPERTIES - LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMTD\"" - ) -else () -set_target_properties(SLPlugin - PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist - ) -endif () - target_link_libraries(SLPlugin llplugin llmessage @@ -49,7 +37,19 @@ target_link_libraries(SLPlugin ll::pluginlibraries ) -if (DARWIN) +if (WINDOWS) + set_target_properties(SLPlugin + PROPERTIES + LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMTD\"" + ) +elseif (DARWIN) + set_target_properties(SLPlugin + PROPERTIES + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_RPATH "@executable_path/../../../../Frameworks;@executable_path/../Frameworks;@executable_path/../Frameworks/plugins" + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist + ) + # Make sure the app bundle has a Resources directory (it will get populated by viewer-manifest.py later) add_custom_command( TARGET SLPlugin POST_BUILD @@ -58,7 +58,7 @@ if (DARWIN) -p ${CMAKE_CURRENT_BINARY_DIR}/$,$,>/SLPlugin.app/Contents/Resources ) -endif (DARWIN) +endif () if (LL_TESTS) ll_deploy_sharedlibs_command(SLPlugin) diff --git a/indra/media_plugins/base/CMakeLists.txt b/indra/media_plugins/base/CMakeLists.txt index 64b6a4228d2..23f503c3458 100644 --- a/indra/media_plugins/base/CMakeLists.txt +++ b/indra/media_plugins/base/CMakeLists.txt @@ -34,5 +34,5 @@ add_library(media_plugin_base ${media_plugin_base_SOURCE_FILES} ) -target_link_libraries( media_plugin_base llplugin ) +target_link_libraries( media_plugin_base llplugin ll::pluginlibraries) target_include_directories( media_plugin_base INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt index 0d1a8339366..ebcf67576dc 100644 --- a/indra/media_plugins/cef/CMakeLists.txt +++ b/indra/media_plugins/cef/CMakeLists.txt @@ -77,16 +77,8 @@ if (DARWIN) PROPERTIES PREFIX "" BUILD_WITH_INSTALL_RPATH 1 - INSTALL_NAME_DIR "@executable_path" + INSTALL_RPATH "@executable_path/../Frameworks" LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" ) - add_custom_command(TARGET media_plugin_cef - POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "@executable_path/Chromium Embedded Framework" - "@executable_path/../../../../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" - "$" - VERBATIM - COMMENT "Fixing path to CEF Framework" - ) - endif (DARWIN) diff --git a/indra/media_plugins/example/CMakeLists.txt b/indra/media_plugins/example/CMakeLists.txt index 41e2353f31c..278dac8c336 100644 --- a/indra/media_plugins/example/CMakeLists.txt +++ b/indra/media_plugins/example/CMakeLists.txt @@ -47,7 +47,7 @@ if (DARWIN) PROPERTIES PREFIX "" BUILD_WITH_INSTALL_RPATH 1 - INSTALL_NAME_DIR "@executable_path" + INSTALL_RPATH "@executable_path/../Frameworks" LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" ) diff --git a/indra/media_plugins/libvlc/CMakeLists.txt b/indra/media_plugins/libvlc/CMakeLists.txt index 202cbed96e6..f9e0810df26 100644 --- a/indra/media_plugins/libvlc/CMakeLists.txt +++ b/indra/media_plugins/libvlc/CMakeLists.txt @@ -50,7 +50,7 @@ if (DARWIN) PROPERTIES PREFIX "" BUILD_WITH_INSTALL_RPATH 1 - INSTALL_NAME_DIR "@executable_path" + INSTALL_RPATH "@executable_path/../Frameworks" LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" ) diff --git a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp index 4240613a0c1..ad0ecaf4abf 100644 --- a/indra/media_plugins/libvlc/media_plugin_libvlc.cpp +++ b/indra/media_plugins/libvlc/media_plugin_libvlc.cpp @@ -174,7 +174,7 @@ void MediaPluginLibVLC::initVLC() }; #if LL_DARWIN - setenv("VLC_PLUGIN_PATH", ".", 1); + setenv("VLC_PLUGIN_PATH", "./plugins", 1); #endif int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index f2aec208a1e..40b6b357044 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2156,10 +2156,8 @@ if (DARWIN) PROPERTIES OUTPUT_NAME "${product}" # From Contents/MacOS/SecondLife, look in Contents/Frameworks - INSTALL_RPATH "@loader_path/../Frameworks" - # SIGH, as of 2018-05-24 (cmake 3.11.1) the INSTALL_RPATH property simply - # does not work. Try this: - LINK_FLAGS "-rpath @loader_path/../Frameworks" + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_RPATH "@executable_path/../Frameworks" MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist" XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${MACOSX_BUNDLE_GUI_IDENTIFIER}" ) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 905f53e50be..df9541d1a32 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -866,9 +866,6 @@ def construct(self): # CEF framework goes inside Contents/Frameworks. # Remember where we parked this car. with self.prefix(src="", dst="Frameworks"): - CEF_framework = "Chromium Embedded Framework.framework" - self.path2basename(relpkgdir, CEF_framework) - CEF_framework = self.dst_path_of(CEF_framework) if self.args.get('bugsplat'): self.path2basename(relpkgdir, "BugsplatMac.framework") @@ -1066,113 +1063,31 @@ def path_optional(src, dst): # Dullahan helper apps go inside SLPlugin.app with self.prefix(dst=os.path.join( "SLPlugin.app", "Contents", "Frameworks")): - - frameworkname = 'Chromium Embedded Framework' - - # This code constructs a relative symlink from the - # target framework folder back to the real CEF framework. - # It needs to be relative so that the symlink still works when - # (as is normal) the user moves the app bundle out of the DMG - # and into the /Applications folder. Note we pass catch=False, - # letting the uncaught exception terminate the process, since - # without this symlink, Second Life web media can't possibly work. - - # It might seem simpler just to symlink Frameworks back to - # the parent of Chromimum Embedded Framework.framework. But - # that would create a symlink cycle, which breaks our - # packaging step. So make a symlink from Chromium Embedded - # Framework.framework to the directory of the same name, which - # is NOT an ancestor of the symlink. - - # from SLPlugin.app/Contents/Frameworks/Chromium Embedded - # Framework.framework back to - # $viewer_app/Contents/Frameworks/Chromium Embedded Framework.framework - SLPlugin_framework = self.relsymlinkf(CEF_framework, catch=False) - - # for all the multiple CEF/Dullahan (as of CEF 76) helper app bundles we need: - for helper in ( - "DullahanHelper", - "DullahanHelper (GPU)", - "DullahanHelper (Renderer)", - "DullahanHelper (Plugin)", - ): - # app is the directory name of the app bundle, with app/Contents/MacOS/helper as the executable - app = helper + ".app" - - # copy DullahanHelper.app - self.path2basename(relpkgdir, app) - - # and fix that up with a Frameworks/CEF symlink too - with self.prefix(dst=os.path.join( - app, 'Contents', 'Frameworks')): - # from Dullahan Helper *.app/Contents/Frameworks/Chromium Embedded - # Framework.framework back to - # SLPlugin.app/Contents/Frameworks/Chromium Embedded Framework.framework - # Since SLPlugin_framework is itself a - # symlink, don't let relsymlinkf() resolve -- - # explicitly call relpath(symlink=True) and - # create that symlink here. - helper_framework = \ - self.symlinkf(self.relpath(SLPlugin_framework, symlink=True), catch=False) - - # change_command includes install_name_tool, the - # -change subcommand and the old framework rpath - # stamped into the executable. To use it with - # run_command(), we must still append the new - # framework path and the pathname of the - # executable to change. - change_command = [ - 'install_name_tool', '-change', - '@rpath/Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework'] - - with self.prefix(dst=os.path.join( - app, 'Contents', 'MacOS')): - # Now self.get_dst_prefix() is, at runtime, - # @executable_path. Locate the helper app - # framework (which is a symlink) from here. - newpath = os.path.join( - '@executable_path', - self.relpath(helper_framework, symlink=True), - frameworkname) - # and restamp the Dullahan Helper executable itself - self.run_command( - change_command + - [newpath, self.dst_path_of(helper)]) - - # SLPlugin plugins - with self.prefix(dst="llplugin"): - dylibexecutable = 'media_plugin_cef.dylib' + # copy CEF plugin self.path2basename("../media_plugins/cef/" + self.args['configuration'], - dylibexecutable) - - # Do this install_name_tool *after* media plugin is copied over. - # Locate the framework lib executable -- relative to - # SLPlugin.app/Contents/MacOS, which will be our - # @executable_path at runtime! - newpath = os.path.join( - '@executable_path', - self.relpath(SLPlugin_framework, executable_path["SLPlugin.app"], - symlink=True), - frameworkname) - # restamp media_plugin_cef.dylib - self.run_command( - change_command + - [newpath, self.dst_path_of(dylibexecutable)]) - - # copy LibVLC plugin itself - dylibexecutable = 'media_plugin_libvlc.dylib' - self.path2basename("../media_plugins/libvlc/" + self.args['configuration'], dylibexecutable) - # add @rpath for the correct LibVLC subfolder - self.run_command(['install_name_tool', '-add_rpath', '@loader_path/lib', self.dst_path_of(dylibexecutable)]) - - # copy LibVLC dynamic libraries - with self.prefix(src=relpkgdir, dst="lib"): + "media_plugin_cef.dylib") + + # copy LibVLC plugin + self.path2basename("../media_plugins/libvlc/" + self.args['configuration'], + "media_plugin_libvlc.dylib") + + # CEF framework and vlc libraries goes inside Contents/Frameworks. + with self.prefix(src=os.path.join(pkgdir, 'lib', 'release')): + self.path("Chromium Embedded Framework.framework") + self.path("DullahanHelper.app") + self.path("DullahanHelper (Alerts).app") + self.path("DullahanHelper (GPU).app") + self.path("DullahanHelper (Renderer).app") + self.path("DullahanHelper (Plugin).app") + + # Copy libvlc self.path( "libvlc*.dylib*" ) # copy LibVLC plugins folder - with self.prefix(src='plugins', dst=""): + with self.prefix(src='plugins', dst="plugins"): self.path( "*.dylib" ) self.path( "plugins.dat" ) + def package_finish(self): imagename = self.installer_base_name() self.set_github_output('imagename', imagename) From 0ae3de8f1e78dc74914ea70e725c8324390f3e97 Mon Sep 17 00:00:00 2001 From: Rye Date: Wed, 27 Aug 2025 23:05:58 -0400 Subject: [PATCH 118/145] Fix cmake to ${CMAKE_COMMAND} to avoid cmake error --- indra/test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index 745c0eedf81..f80286a630c 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -114,7 +114,7 @@ if (LL_TESTS) # but the CMake $ generator expression isn't evaluated by # CREATE_LINK, so fudge it. add_custom_command( TARGET lltest POST_BUILD - COMMAND cmake -E create_symlink ${SHARED_LIB_STAGING_DIR} ${CMAKE_BINARY_DIR}/test/Resources + COMMAND ${CMAKE_COMMAND} -E create_symlink ${SHARED_LIB_STAGING_DIR} ${CMAKE_BINARY_DIR}/test/Resources ) endif() endif (LL_TESTS) From 3ea1d87a42bfc6aba367b1285e7bb6bdf49f8364 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 2 Sep 2025 23:26:16 +0300 Subject: [PATCH 119/145] #4587 Shaders sometimes do not match the shader settings Ensure versions get matched reliably --- indra/llrender/llshadermgr.cpp | 36 ++++++++++++++++++++++------- indra/llrender/llshadermgr.h | 4 ++-- indra/newview/llviewershadermgr.cpp | 11 +++++++-- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 4807c122263..0ec532a55bd 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -989,16 +989,17 @@ bool LLShaderMgr::validateProgramObject(GLuint obj) return success; } -void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version, const LLUUID& current_cache_version) +void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version, const LLUUID& current_cache_version, bool second_instance) { + LL_PROFILE_ZONE_SCOPED; LL_INFOS() << "Initializing shader cache" << LL_ENDL; mShaderCacheEnabled = gGLManager.mGLVersion >= 4.09 && enabled; - if(!mShaderCacheEnabled || mShaderCacheInitialized) + if(!mShaderCacheEnabled || mShaderCacheVersion.notNull()) return; - mShaderCacheInitialized = true; + mShaderCacheVersion = current_cache_version; mShaderCacheDir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "shader_cache"); LLFile::mkdir(mShaderCacheDir); @@ -1007,16 +1008,19 @@ void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version, std::string meta_out_path = gDirUtilp->add(mShaderCacheDir, "shaderdata.llsd"); if (gDirUtilp->fileExists(meta_out_path)) { + LL_PROFILE_ZONE_NAMED("shader_cache"); LL_INFOS() << "Loading shader cache metadata" << LL_ENDL; llifstream instream(meta_out_path); LLSD in_data; + // todo: this is likely very expensive to parse, should use binary LLSDSerialize::fromNotation(in_data, instream, LLSDSerialize::SIZE_UNLIMITED); instream.close(); - if (old_cache_version == current_cache_version) + if (old_cache_version == current_cache_version + && in_data["version"].asUUID() == current_cache_version) { - for (const auto& data_pair : llsd::inMap(in_data)) + for (const auto& data_pair : llsd::inMap(in_data["shaders"])) { ProgramBinaryData binary_info = ProgramBinaryData(); binary_info.mBinaryFormat = data_pair.second["binary_format"].asInteger(); @@ -1025,11 +1029,15 @@ void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version, mShaderBinaryCache.insert_or_assign(LLUUID(data_pair.first), binary_info); } } - else + else if (!second_instance) { LL_INFOS() << "Shader cache version mismatch detected. Purging." << LL_ENDL; clearShaderCache(); } + else + { + LL_INFOS() << "Shader cache version mismatch detected." << LL_ENDL; + } } } } @@ -1046,10 +1054,22 @@ void LLShaderMgr::clearShaderCache() void LLShaderMgr::persistShaderCacheMetadata() { if(!mShaderCacheEnabled) return; + if (mShaderCacheVersion.isNull()) + { + LL_WARNS() << "Attempted to save shader cache with no version set" << LL_ENDL; + return; + } LL_INFOS() << "Persisting shader cache metadata to disk" << LL_ENDL; - LLSD out = LLSD::emptyMap(); + LLSD out; + // Settings and shader cache get saved at different time, thus making + // RenderShaderCacheVersion unreliable when running multiple viewer + // instances, or for cases where viewer crashes before saving settings. + // Dupplicate version to the cache itself. + out["version"] = mShaderCacheVersion; + out["shaders"] = LLSD::emptyMap(); + LLSD &shaders = out["shaders"]; static const F32 LRU_TIME = (60.f * 60.f) * 24.f * 7.f; // 14 days const F32 current_time = (F32)LLTimer::getTotalSeconds(); @@ -1068,7 +1088,7 @@ void LLShaderMgr::persistShaderCacheMetadata() data["binary_format"] = LLSD::Integer(shader_metadata.mBinaryFormat); data["binary_size"] = LLSD::Integer(shader_metadata.mBinaryLength); data["last_used"] = LLSD::Real(shader_metadata.mLastUsedTime); - out[it->first.asString()] = data; + shaders[it->first.asString()] = data; ++it; } } diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 46788841a5d..1b638e6e065 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -363,7 +363,7 @@ class LLShaderMgr // Implemented in the application to actually update out of date uniforms for a particular shader virtual void updateShaderUniforms(LLGLSLShader * shader) = 0; // Pure Virtual - void initShaderCache(bool enabled, const LLUUID& old_cache_version, const LLUUID& current_cache_version); + void initShaderCache(bool enabled, const LLUUID& old_cache_version, const LLUUID& current_cache_version, bool second_instance); void clearShaderCache(); void persistShaderCacheMetadata(); @@ -387,7 +387,7 @@ class LLShaderMgr F32 mLastUsedTime = 0.0; }; std::map mShaderBinaryCache; - bool mShaderCacheInitialized = false; + LLUUID mShaderCacheVersion; bool mShaderCacheEnabled = false; std::string mShaderCacheDir; diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index a0a9906724e..a9c58d5a067 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -545,7 +545,11 @@ void LLViewerShaderMgr::setShaders() gSavedSettings.setString("RenderShaderCacheVersion", current_cache_version.asString()); } - initShaderCache(shader_cache_enabled, old_cache_version, current_cache_version); + initShaderCache( + shader_cache_enabled, + old_cache_version, + current_cache_version, + LLAppViewer::instance()->isSecondInstance()); } static LLCachedControl max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16); @@ -703,7 +707,10 @@ void LLViewerShaderMgr::setShaders() loaded = loaded && loadShadersDeferred(); llassert(loaded); - persistShaderCacheMetadata(); + if (!LLAppViewer::instance()->isSecondInstance()) + { + persistShaderCacheMetadata(); + } if (gViewerWindow) { From 46f325b7db41ac855d35e3ab50ad915dd075de1e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 2 Sep 2025 23:29:06 +0300 Subject: [PATCH 120/145] #4587 Make shader cache reading faster --- indra/llrender/llshadermgr.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 0ec532a55bd..a4d5282b0c8 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -992,7 +992,7 @@ bool LLShaderMgr::validateProgramObject(GLuint obj) void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version, const LLUUID& current_cache_version, bool second_instance) { LL_PROFILE_ZONE_SCOPED; - LL_INFOS() << "Initializing shader cache" << LL_ENDL; + LL_INFOS("ShaderMgr") << "Initializing shader cache" << LL_ENDL; mShaderCacheEnabled = gGLManager.mGLVersion >= 4.09 && enabled; @@ -1009,12 +1009,12 @@ void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version, if (gDirUtilp->fileExists(meta_out_path)) { LL_PROFILE_ZONE_NAMED("shader_cache"); - LL_INFOS() << "Loading shader cache metadata" << LL_ENDL; + LL_INFOS("ShaderMgr") << "Loading shader cache metadata" << LL_ENDL; - llifstream instream(meta_out_path); + llifstream instream(meta_out_path, std::ifstream::in | std::ifstream::binary); LLSD in_data; // todo: this is likely very expensive to parse, should use binary - LLSDSerialize::fromNotation(in_data, instream, LLSDSerialize::SIZE_UNLIMITED); + LLSDSerialize::fromBinary(in_data, instream, LLSDSerialize::SIZE_UNLIMITED); instream.close(); if (old_cache_version == current_cache_version @@ -1031,12 +1031,12 @@ void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version, } else if (!second_instance) { - LL_INFOS() << "Shader cache version mismatch detected. Purging." << LL_ENDL; + LL_INFOS("ShaderMgr") << "Shader cache version mismatch detected. Purging." << LL_ENDL; clearShaderCache(); } else { - LL_INFOS() << "Shader cache version mismatch detected." << LL_ENDL; + LL_INFOS("ShaderMgr") << "Shader cache version mismatch detected." << LL_ENDL; } } } @@ -1045,7 +1045,7 @@ void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version, void LLShaderMgr::clearShaderCache() { std::string shader_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "shader_cache"); - LL_INFOS() << "Removing shader cache at " << shader_cache << LL_ENDL; + LL_INFOS("ShaderMgr") << "Removing shader cache at " << shader_cache << LL_ENDL; const std::string mask = "*"; gDirUtilp->deleteFilesInDir(shader_cache, mask); mShaderBinaryCache.clear(); @@ -1056,11 +1056,11 @@ void LLShaderMgr::persistShaderCacheMetadata() if(!mShaderCacheEnabled) return; if (mShaderCacheVersion.isNull()) { - LL_WARNS() << "Attempted to save shader cache with no version set" << LL_ENDL; + LL_WARNS("ShaderMgr") << "Attempted to save shader cache with no version set" << LL_ENDL; return; } - LL_INFOS() << "Persisting shader cache metadata to disk" << LL_ENDL; + LL_INFOS("ShaderMgr") << "Persisting shader cache metadata to disk" << LL_ENDL; LLSD out; // Settings and shader cache get saved at different time, thus making @@ -1094,8 +1094,13 @@ void LLShaderMgr::persistShaderCacheMetadata() } std::string meta_out_path = gDirUtilp->add(mShaderCacheDir, "shaderdata.llsd"); - llofstream outstream(meta_out_path); - LLSDSerialize::toNotation(out, outstream); + llofstream outstream(meta_out_path, std::ios_base::out | std::ios_base::binary); + if (!outstream.is_open()) + { + LL_WARNS("ShaderMgr") << "Failed to open file. Unable to save shader cache to: " << mShaderCacheDir << LL_ENDL; + return; + } + LLSDSerialize::toBinary(out, outstream); outstream.close(); } From a4f58810f4c4f6e66246426aa3ca120e713049e0 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 3 Sep 2025 22:29:35 +0300 Subject: [PATCH 121/145] #4623 Shared Media on HUDs not loading Looks like a merge between a commit that affected mScreenPixelArea and a commit that added a return value resulted in reordered calls. --- indra/newview/llviewercamera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index 511293a8089..af6c78d8e57 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -157,9 +157,9 @@ bool LLViewerCamera::updateCameraLocation(const LLVector3 ¢er, const LLVecto // update pixel meter ratio using default fov, not modified one mPixelMeterRatio = (F32)(getViewHeightInPixels()/ (2.f*tanf(mCameraFOVDefault*0.5f))); // update screen pixel area + mScreenPixelArea =(S32)((F32)getViewHeightInPixels() * ((F32)getViewHeightInPixels() * getAspect())); return true; - mScreenPixelArea =(S32)((F32)getViewHeightInPixels() * ((F32)getViewHeightInPixels() * getAspect())); } const LLMatrix4 &LLViewerCamera::getProjection() const From f5c872a12dc5c8e47f61b80056d21f90da2cd689 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 4 Sep 2025 20:56:11 +0300 Subject: [PATCH 122/145] p#470 Fix wrong release notes being shown. --- indra/newview/llstartup.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 5df7eca5f5d..bf7c58a3cb0 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -57,6 +57,7 @@ #include "lllocationhistory.h" #include "llgltfmateriallist.h" #include "llimageworker.h" +#include "llregex.h" #include "llloginflags.h" #include "llmd5.h" @@ -2558,6 +2559,27 @@ void release_notes_coro(const std::string url) LLWeb::loadURLInternal(url); } +void validate_release_notes_coro(const std::string url) +{ + LLVersionInfo& versionInfo(LLVersionInfo::instance()); + const boost::regex version_regex(R"(\b\d+\.\d+\.\d+\.\d+\b)"); + + if (url.find(versionInfo.getVersion()) == std::string::npos // has no our build version + && ll_regex_search(url, version_regex)) // has any version + { + LL_INFOS() << "Received release notes url \"" << url << "\" wwith mismatching build, falling back to locally generated url" << LL_ENDL; + // Updater only provides notes for a most recent version, if it is not + // the current one, fall back to the hardcoded URL. + LLSD info(LLAppViewer::instance()->getViewerInfo()); + std::string alt_url = info["VIEWER_RELEASE_NOTES_URL"].asString(); + release_notes_coro(alt_url); + } + else + { + release_notes_coro(url); + } +} + /** * Check if user is running a new version of the viewer. * Display the Release Notes if it's not overriden by the "UpdaterShowReleaseNotes" setting. @@ -2591,7 +2613,7 @@ void show_release_notes_if_required() "showrelnotes", [](const LLSD& url) { LLCoros::instance().launch("releaseNotesCoro", - boost::bind(&release_notes_coro, url.asString())); + boost::bind(&validate_release_notes_coro, url.asString())); return false; }); } From 94e45ca2e60b4013a4e38d8f2c1fe8dad4207c3a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 5 Sep 2025 15:09:11 +0300 Subject: [PATCH 123/145] Replace boost filesystem with std filesystem Build fixes, instead of resolving unclear boost filesystem errors just updated to std in affected places. --- indra/llfilesystem/lldir.cpp | 32 ++++++------- indra/llfilesystem/lldiriterator.cpp | 4 +- indra/llfilesystem/lldiskcache.cpp | 70 ++++++++++++++-------------- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp index ea33a3bb906..06f5dd2f771 100644 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -43,7 +43,7 @@ #include "lldiriterator.h" #include "stringize.h" #include "llstring.h" -#include +#include #include #include #include @@ -103,24 +103,24 @@ std::vector LLDir::getFilesInDir(const std::string &dirname) //Returns a vector of fullpath filenames. #ifdef LL_WINDOWS // or BOOST_WINDOWS_API - boost::filesystem::path p(ll_convert(dirname)); + std::filesystem::path p(ll_convert(dirname)); #else - boost::filesystem::path p(dirname); + std::filesystem::path p(dirname); #endif std::vector v; - boost::system::error_code ec; - if (exists(p, ec) && !ec.failed()) + std::error_code ec; + if (std::filesystem::exists(p, ec) && ec.value() == 0) { - if (is_directory(p, ec) && !ec.failed()) + if (is_directory(p, ec) && ec.value() == 0) { - boost::filesystem::directory_iterator end_iter; - for (boost::filesystem::directory_iterator dir_itr(p); + std::filesystem::directory_iterator end_iter; + for (std::filesystem::directory_iterator dir_itr(p); dir_itr != end_iter; ++dir_itr) { - if (boost::filesystem::is_regular_file(dir_itr->status())) + if (std::filesystem::is_regular_file(dir_itr->status())) { v.push_back(dir_itr->path().filename().string()); } @@ -197,24 +197,24 @@ U32 LLDir::deleteDirAndContents(const std::string& dir_name) try { #ifdef LL_WINDOWS // or BOOST_WINDOWS_API - boost::filesystem::path dir_path(ll_convert(dir_name)); + std::filesystem::path dir_path(ll_convert(dir_name)); #else - boost::filesystem::path dir_path(dir_name); + std::filesystem::path dir_path(dir_name); #endif - if (boost::filesystem::exists(dir_path)) + if (std::filesystem::exists(dir_path)) { - if (!boost::filesystem::is_empty(dir_path)) + if (!std::filesystem::is_empty(dir_path)) { // Directory has content - num_deleted = (U32)boost::filesystem::remove_all(dir_path); + num_deleted = (U32)std::filesystem::remove_all(dir_path); } else { // Directory is empty - boost::filesystem::remove(dir_path); + std::filesystem::remove(dir_path); } } } - catch (boost::filesystem::filesystem_error &er) + catch (std::filesystem::filesystem_error &er) { LL_WARNS() << "Failed to delete " << dir_name << " with error " << er.code().message() << LL_ENDL; } diff --git a/indra/llfilesystem/lldiriterator.cpp b/indra/llfilesystem/lldiriterator.cpp index e8c37389d2a..28a93f1446d 100644 --- a/indra/llfilesystem/lldiriterator.cpp +++ b/indra/llfilesystem/lldiriterator.cpp @@ -28,9 +28,9 @@ #include "fix_macros.h" #include "llregex.h" -#include +#include -namespace fs = boost::filesystem; +namespace fs = std::filesystem; static std::string glob_to_regex(const std::string& glob); diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp index e971e1885a2..417577369fb 100644 --- a/indra/llfilesystem/lldiskcache.cpp +++ b/indra/llfilesystem/lldiskcache.cpp @@ -34,7 +34,7 @@ #include "llapp.h" #include "llassettype.h" #include "lldir.h" -#include +#include #include #include "lldiskcache.h" @@ -83,7 +83,7 @@ LLDiskCache::LLDiskCache(const std::string& cache_dir, // garbage.) // Other situation: B is trimming the cache and A wants to read a file that is -// about to get deleted. boost::filesystem::remove does whatever it is doing +// about to get deleted. std::filesystem::remove does whatever it is doing // before actually deleting the file. If A opens the file before the file is // actually gone, the OS call from B to delete the file will fail since the OS // will prevent this. B continues with the next file. If the file is already @@ -96,10 +96,10 @@ void LLDiskCache::purge() LL_INFOS() << "Total dir size before purge is " << dirFileSize(sCacheDir) << LL_ENDL; } - boost::system::error_code ec; + std::error_code ec; auto start_time = std::chrono::high_resolution_clock::now(); - typedef std::pair> file_info_t; + typedef std::pair> file_info_t; std::vector file_info; #if LL_WINDOWS @@ -107,23 +107,23 @@ void LLDiskCache::purge() #else std::string cache_path(sCacheDir); #endif - if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed()) + if (std::filesystem::is_directory(cache_path, ec) && ec.value() == 0) { - boost::filesystem::directory_iterator iter(cache_path, ec); - while (iter != boost::filesystem::directory_iterator() && !ec.failed()) + std::filesystem::directory_iterator iter(cache_path, ec); + while (iter != std::filesystem::directory_iterator() && ec.value() == 0) { - if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed()) + if (std::filesystem::is_regular_file(*iter, ec) && ec.value() == 0) { if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos) { - uintmax_t file_size = boost::filesystem::file_size(*iter, ec); - if (ec.failed()) + uintmax_t file_size = std::filesystem::file_size(*iter, ec); + if (ec.value() != 0) { continue; } const std::string file_path = (*iter).path().string(); - const std::time_t file_time = boost::filesystem::last_write_time(*iter, ec); - if (ec.failed()) + const std::filesystem::file_time_type file_time = std::filesystem::last_write_time(*iter, ec); + if (ec.value() != 0) { continue; } @@ -159,8 +159,8 @@ void LLDiskCache::purge() } if (should_remove) { - boost::filesystem::remove(entry.second.second, ec); - if (ec.failed()) + std::filesystem::remove(entry.second.second, ec); + if (ec.value() != 0) { LL_WARNS() << "Failed to delete cache file " << entry.second.second << ": " << ec.message() << LL_ENDL; } @@ -224,23 +224,23 @@ void LLDiskCache::clearCache() * the component files but it's called infrequently so it's * likely just fine */ - boost::system::error_code ec; + std::error_code ec; #if LL_WINDOWS std::wstring cache_path(ll_convert(sCacheDir)); #else std::string cache_path(sCacheDir); #endif - if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed()) + if (std::filesystem::is_directory(cache_path, ec) && ec.value() == 0) { - boost::filesystem::directory_iterator iter(cache_path, ec); - while (iter != boost::filesystem::directory_iterator() && !ec.failed()) + std::filesystem::directory_iterator iter(cache_path, ec); + while (iter != std::filesystem::directory_iterator() && ec.value() == 0) { - if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed()) + if (std::filesystem::is_regular_file(*iter, ec) && ec.value() == 0) { if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos) { - boost::filesystem::remove(*iter, ec); - if (ec.failed()) + std::filesystem::remove(*iter, ec); + if (ec.value() != 0) { LL_WARNS() << "Failed to delete cache file " << *iter << ": " << ec.message() << LL_ENDL; } @@ -257,24 +257,24 @@ void LLDiskCache::removeOldVFSFiles() static const char CACHE_FORMAT[] = "inv.llsd"; static const char DB_FORMAT[] = "db2.x"; - boost::system::error_code ec; + std::error_code ec; #if LL_WINDOWS std::wstring cache_path(ll_convert(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""))); #else std::string cache_path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "")); #endif - if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed()) + if (std::filesystem::is_directory(cache_path, ec) && ec.value() == 0) { - boost::filesystem::directory_iterator iter(cache_path, ec); - while (iter != boost::filesystem::directory_iterator() && !ec.failed()) + std::filesystem::directory_iterator iter(cache_path, ec); + while (iter != std::filesystem::directory_iterator() && ec.value() == 0) { - if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed()) + if (std::filesystem::is_regular_file(*iter, ec) && ec.value() == 0) { if (((*iter).path().string().find(CACHE_FORMAT) != std::string::npos) || ((*iter).path().string().find(DB_FORMAT) != std::string::npos)) { - boost::filesystem::remove(*iter, ec); - if (ec.failed()) + std::filesystem::remove(*iter, ec); + if (ec.value() != 0) { LL_WARNS() << "Failed to delete cache file " << *iter << ": " << ec.message() << LL_ENDL; } @@ -298,23 +298,23 @@ uintmax_t LLDiskCache::dirFileSize(const std::string& dir) * so if performance is ever an issue, optimizing this or removing it altogether, * is an easy win. */ - boost::system::error_code ec; + std::error_code ec; #if LL_WINDOWS std::wstring dir_path(ll_convert(dir)); #else std::string dir_path(dir); #endif - if (boost::filesystem::is_directory(dir_path, ec) && !ec.failed()) + if (std::filesystem::is_directory(dir_path, ec) && ec.value() == 0) { - boost::filesystem::directory_iterator iter(dir_path, ec); - while (iter != boost::filesystem::directory_iterator() && !ec.failed()) + std::filesystem::directory_iterator iter(dir_path, ec); + while (iter != std::filesystem::directory_iterator() && ec.value() == 0) { - if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed()) + if (std::filesystem::is_regular_file(*iter, ec) && ec.value() == 0) { if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos) { - uintmax_t file_size = boost::filesystem::file_size(*iter, ec); - if (!ec.failed()) + uintmax_t file_size = std::filesystem::file_size(*iter, ec); + if (ec.value() == 0) { total_file_size += file_size; } From 12704b941132ec6fb6ca62da007c3ec02292c872 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 5 Sep 2025 13:23:09 +0300 Subject: [PATCH 124/145] viewer-cef build fixes --- indra/CMakeLists.txt | 8 +- indra/cmake/Boost.cmake | 148 ++++++++++++++++------- indra/cmake/LLKDU.cmake | 17 ++- indra/llkdu/tests/llimagej2ckdu_test.cpp | 1 + 4 files changed, 121 insertions(+), 53 deletions(-) diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 455e7980e2e..6504002dd98 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -11,8 +11,12 @@ ## We're not there yet, but once done, there is a kludge in Linking.cmake # "if(${CMAKE_VERSION} VERSION_LESS "3.20.0")" that can also be removed cmake_minimum_required(VERSION 3.16.0...4.0 FATAL_ERROR) -cmake_policy(SET CMP0156 NEW) -cmake_policy(SET CMP0179 NEW) +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.29.0") + cmake_policy(SET CMP0156 NEW) +endif() +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.31.0") + cmake_policy(SET CMP0179 NEW) +endif() set(ROOT_PROJECT_NAME "SecondLife" CACHE STRING "The root project/makefile/solution name. Defaults to SecondLife.") diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 7b3882c936e..b57c33c3e00 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -16,53 +16,107 @@ use_prebuilt_binary(boost) # with the address size. set(addrsfx "-x${ADDRESS_SIZE}") -find_library(BOOST_CONTEXT_LIBRARY - NAMES - boost_context-mt - boost_context-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(BOOST_FIBER_LIBRARY - NAMES - boost_fiber-mt - boost_fiber-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(BOOST_FILESYSTEM_LIBRARY - NAMES - boost_filesystem-mt - boost_filesystem-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(BOOST_PROGRAMOPTIONS_LIBRARY - NAMES - boost_program_options-mt - boost_program_options-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(BOOST_REGEX_LIBRARY - NAMES - boost_regex-mt - boost_regex-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(BOOST_SYSTEM_LIBRARY - NAMES - boost_system-mt - boost_system-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(BOOST_THREAD_LIBRARY - NAMES - boost_thread-mt - boost_thread-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(BOOST_URL_LIBRARY - NAMES - boost_url-mt - boost_url-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) +if (WINDOWS) + + find_library(BOOST_CONTEXT_LIBRARY + NAMES + libboost_context-mt + libboost_context-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_FIBER_LIBRARY + NAMES + libboost_fiber-mt + libboost_fiber-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_FILESYSTEM_LIBRARY + NAMES + libboost_filesystem-mt + libboost_filesystem-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_PROGRAMOPTIONS_LIBRARY + NAMES + libboost_program_options-mt + libboost_program_options-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_REGEX_LIBRARY + NAMES + libboost_regex-mt + libboost_regex-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_SYSTEM_LIBRARY + NAMES + libboost_system-mt + libboost_system-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_THREAD_LIBRARY + NAMES + libboost_thread-mt + libboost_thread-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_URL_LIBRARY + NAMES + libboost_url-mt + libboost_url-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + +else (WINDOWS) + + find_library(BOOST_CONTEXT_LIBRARY + NAMES + boost_context-mt + boost_context-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_FIBER_LIBRARY + NAMES + boost_fiber-mt + boost_fiber-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_FILESYSTEM_LIBRARY + NAMES + boost_filesystem-mt + boost_filesystem-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_PROGRAMOPTIONS_LIBRARY + NAMES + boost_program_options-mt + boost_program_options-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_REGEX_LIBRARY + NAMES + boost_regex-mt + boost_regex-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_SYSTEM_LIBRARY + NAMES + boost_system-mt + boost_system-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_THREAD_LIBRARY + NAMES + boost_thread-mt + boost_thread-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + find_library(BOOST_URL_LIBRARY + NAMES + boost_url-mt + boost_url-mt${addrsfx} + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + +endif (WINDOWS) target_link_libraries(ll::boost INTERFACE ${BOOST_FIBER_LIBRARY} diff --git a/indra/cmake/LLKDU.cmake b/indra/cmake/LLKDU.cmake index dc98335a28e..7680ab7b542 100644 --- a/indra/cmake/LLKDU.cmake +++ b/indra/cmake/LLKDU.cmake @@ -14,10 +14,19 @@ if (USE_KDU) include(Prebuilt) use_prebuilt_binary(kdu) - find_library(KDU_LIBRARY - NAMES - kdu - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + if (WINDOWS) + find_library(KDU_LIBRARY + NAMES + kdu + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + else (WINDOWS) + find_library(KDU_LIBRARY + NAMES + libkdu.a + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + + endif (WINDOWS) target_link_libraries(ll::kdu INTERFACE ${KDU_LIBRARY}) diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp index 36b79047b68..bc52a15c4af 100644 --- a/indra/llkdu/tests/llimagej2ckdu_test.cpp +++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp @@ -80,6 +80,7 @@ U8* LLImageBase::getData() { return NULL; } U8* LLImageBase::reallocateData(S32 ) { return NULL; } void LLImageBase::sanityCheck() { } void LLImageBase::setSize(S32 , S32 , S32 ) { } +bool LLImageBase::isBufferInvalid() const { return false; } LLImageJ2CImpl::~LLImageJ2CImpl() { } From 94cfce4a4d2dbc799e5e8a3495a628ae85d4cffe Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Fri, 5 Sep 2025 13:44:57 -0700 Subject: [PATCH 125/145] Revert "Replace boost filesystem with std filesystem" This reverts commit 94e45ca2e60b4013a4e38d8f2c1fe8dad4207c3a. --- indra/llfilesystem/lldir.cpp | 32 ++++++------- indra/llfilesystem/lldiriterator.cpp | 4 +- indra/llfilesystem/lldiskcache.cpp | 70 ++++++++++++++-------------- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp index 06f5dd2f771..ea33a3bb906 100644 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -43,7 +43,7 @@ #include "lldiriterator.h" #include "stringize.h" #include "llstring.h" -#include +#include #include #include #include @@ -103,24 +103,24 @@ std::vector LLDir::getFilesInDir(const std::string &dirname) //Returns a vector of fullpath filenames. #ifdef LL_WINDOWS // or BOOST_WINDOWS_API - std::filesystem::path p(ll_convert(dirname)); + boost::filesystem::path p(ll_convert(dirname)); #else - std::filesystem::path p(dirname); + boost::filesystem::path p(dirname); #endif std::vector v; - std::error_code ec; - if (std::filesystem::exists(p, ec) && ec.value() == 0) + boost::system::error_code ec; + if (exists(p, ec) && !ec.failed()) { - if (is_directory(p, ec) && ec.value() == 0) + if (is_directory(p, ec) && !ec.failed()) { - std::filesystem::directory_iterator end_iter; - for (std::filesystem::directory_iterator dir_itr(p); + boost::filesystem::directory_iterator end_iter; + for (boost::filesystem::directory_iterator dir_itr(p); dir_itr != end_iter; ++dir_itr) { - if (std::filesystem::is_regular_file(dir_itr->status())) + if (boost::filesystem::is_regular_file(dir_itr->status())) { v.push_back(dir_itr->path().filename().string()); } @@ -197,24 +197,24 @@ U32 LLDir::deleteDirAndContents(const std::string& dir_name) try { #ifdef LL_WINDOWS // or BOOST_WINDOWS_API - std::filesystem::path dir_path(ll_convert(dir_name)); + boost::filesystem::path dir_path(ll_convert(dir_name)); #else - std::filesystem::path dir_path(dir_name); + boost::filesystem::path dir_path(dir_name); #endif - if (std::filesystem::exists(dir_path)) + if (boost::filesystem::exists(dir_path)) { - if (!std::filesystem::is_empty(dir_path)) + if (!boost::filesystem::is_empty(dir_path)) { // Directory has content - num_deleted = (U32)std::filesystem::remove_all(dir_path); + num_deleted = (U32)boost::filesystem::remove_all(dir_path); } else { // Directory is empty - std::filesystem::remove(dir_path); + boost::filesystem::remove(dir_path); } } } - catch (std::filesystem::filesystem_error &er) + catch (boost::filesystem::filesystem_error &er) { LL_WARNS() << "Failed to delete " << dir_name << " with error " << er.code().message() << LL_ENDL; } diff --git a/indra/llfilesystem/lldiriterator.cpp b/indra/llfilesystem/lldiriterator.cpp index 28a93f1446d..e8c37389d2a 100644 --- a/indra/llfilesystem/lldiriterator.cpp +++ b/indra/llfilesystem/lldiriterator.cpp @@ -28,9 +28,9 @@ #include "fix_macros.h" #include "llregex.h" -#include +#include -namespace fs = std::filesystem; +namespace fs = boost::filesystem; static std::string glob_to_regex(const std::string& glob); diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp index 417577369fb..e971e1885a2 100644 --- a/indra/llfilesystem/lldiskcache.cpp +++ b/indra/llfilesystem/lldiskcache.cpp @@ -34,7 +34,7 @@ #include "llapp.h" #include "llassettype.h" #include "lldir.h" -#include +#include #include #include "lldiskcache.h" @@ -83,7 +83,7 @@ LLDiskCache::LLDiskCache(const std::string& cache_dir, // garbage.) // Other situation: B is trimming the cache and A wants to read a file that is -// about to get deleted. std::filesystem::remove does whatever it is doing +// about to get deleted. boost::filesystem::remove does whatever it is doing // before actually deleting the file. If A opens the file before the file is // actually gone, the OS call from B to delete the file will fail since the OS // will prevent this. B continues with the next file. If the file is already @@ -96,10 +96,10 @@ void LLDiskCache::purge() LL_INFOS() << "Total dir size before purge is " << dirFileSize(sCacheDir) << LL_ENDL; } - std::error_code ec; + boost::system::error_code ec; auto start_time = std::chrono::high_resolution_clock::now(); - typedef std::pair> file_info_t; + typedef std::pair> file_info_t; std::vector file_info; #if LL_WINDOWS @@ -107,23 +107,23 @@ void LLDiskCache::purge() #else std::string cache_path(sCacheDir); #endif - if (std::filesystem::is_directory(cache_path, ec) && ec.value() == 0) + if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed()) { - std::filesystem::directory_iterator iter(cache_path, ec); - while (iter != std::filesystem::directory_iterator() && ec.value() == 0) + boost::filesystem::directory_iterator iter(cache_path, ec); + while (iter != boost::filesystem::directory_iterator() && !ec.failed()) { - if (std::filesystem::is_regular_file(*iter, ec) && ec.value() == 0) + if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed()) { if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos) { - uintmax_t file_size = std::filesystem::file_size(*iter, ec); - if (ec.value() != 0) + uintmax_t file_size = boost::filesystem::file_size(*iter, ec); + if (ec.failed()) { continue; } const std::string file_path = (*iter).path().string(); - const std::filesystem::file_time_type file_time = std::filesystem::last_write_time(*iter, ec); - if (ec.value() != 0) + const std::time_t file_time = boost::filesystem::last_write_time(*iter, ec); + if (ec.failed()) { continue; } @@ -159,8 +159,8 @@ void LLDiskCache::purge() } if (should_remove) { - std::filesystem::remove(entry.second.second, ec); - if (ec.value() != 0) + boost::filesystem::remove(entry.second.second, ec); + if (ec.failed()) { LL_WARNS() << "Failed to delete cache file " << entry.second.second << ": " << ec.message() << LL_ENDL; } @@ -224,23 +224,23 @@ void LLDiskCache::clearCache() * the component files but it's called infrequently so it's * likely just fine */ - std::error_code ec; + boost::system::error_code ec; #if LL_WINDOWS std::wstring cache_path(ll_convert(sCacheDir)); #else std::string cache_path(sCacheDir); #endif - if (std::filesystem::is_directory(cache_path, ec) && ec.value() == 0) + if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed()) { - std::filesystem::directory_iterator iter(cache_path, ec); - while (iter != std::filesystem::directory_iterator() && ec.value() == 0) + boost::filesystem::directory_iterator iter(cache_path, ec); + while (iter != boost::filesystem::directory_iterator() && !ec.failed()) { - if (std::filesystem::is_regular_file(*iter, ec) && ec.value() == 0) + if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed()) { if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos) { - std::filesystem::remove(*iter, ec); - if (ec.value() != 0) + boost::filesystem::remove(*iter, ec); + if (ec.failed()) { LL_WARNS() << "Failed to delete cache file " << *iter << ": " << ec.message() << LL_ENDL; } @@ -257,24 +257,24 @@ void LLDiskCache::removeOldVFSFiles() static const char CACHE_FORMAT[] = "inv.llsd"; static const char DB_FORMAT[] = "db2.x"; - std::error_code ec; + boost::system::error_code ec; #if LL_WINDOWS std::wstring cache_path(ll_convert(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""))); #else std::string cache_path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "")); #endif - if (std::filesystem::is_directory(cache_path, ec) && ec.value() == 0) + if (boost::filesystem::is_directory(cache_path, ec) && !ec.failed()) { - std::filesystem::directory_iterator iter(cache_path, ec); - while (iter != std::filesystem::directory_iterator() && ec.value() == 0) + boost::filesystem::directory_iterator iter(cache_path, ec); + while (iter != boost::filesystem::directory_iterator() && !ec.failed()) { - if (std::filesystem::is_regular_file(*iter, ec) && ec.value() == 0) + if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed()) { if (((*iter).path().string().find(CACHE_FORMAT) != std::string::npos) || ((*iter).path().string().find(DB_FORMAT) != std::string::npos)) { - std::filesystem::remove(*iter, ec); - if (ec.value() != 0) + boost::filesystem::remove(*iter, ec); + if (ec.failed()) { LL_WARNS() << "Failed to delete cache file " << *iter << ": " << ec.message() << LL_ENDL; } @@ -298,23 +298,23 @@ uintmax_t LLDiskCache::dirFileSize(const std::string& dir) * so if performance is ever an issue, optimizing this or removing it altogether, * is an easy win. */ - std::error_code ec; + boost::system::error_code ec; #if LL_WINDOWS std::wstring dir_path(ll_convert(dir)); #else std::string dir_path(dir); #endif - if (std::filesystem::is_directory(dir_path, ec) && ec.value() == 0) + if (boost::filesystem::is_directory(dir_path, ec) && !ec.failed()) { - std::filesystem::directory_iterator iter(dir_path, ec); - while (iter != std::filesystem::directory_iterator() && ec.value() == 0) + boost::filesystem::directory_iterator iter(dir_path, ec); + while (iter != boost::filesystem::directory_iterator() && !ec.failed()) { - if (std::filesystem::is_regular_file(*iter, ec) && ec.value() == 0) + if (boost::filesystem::is_regular_file(*iter, ec) && !ec.failed()) { if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos) { - uintmax_t file_size = std::filesystem::file_size(*iter, ec); - if (ec.value() == 0) + uintmax_t file_size = boost::filesystem::file_size(*iter, ec); + if (!ec.failed()) { total_file_size += file_size; } From 789a64b0def7b404ab23b505482882f4820c42e3 Mon Sep 17 00:00:00 2001 From: Callum Prentice Date: Fri, 5 Sep 2025 13:45:47 -0700 Subject: [PATCH 126/145] Incorporate the latest buld of KDU 8.4.1 with the universal macos libs --- autobuild.xml | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 7581f719dc3..c52fc65176f 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1040,11 +1040,11 @@ creds github hash - 243709fbbb58a91dca81d16df650e9c6ff910d0d + da318f0813e4126d90e35b22a8dce235e908707a hash_algorithm sha1 url - https://api.github.com/repos/secondlife/3p-kdu/releases/assets/202118207 + https://api.github.com/repos/secondlife/3p-kdu/releases/assets/208381808 name darwin64 @@ -1056,11 +1056,11 @@ creds github hash - 7fd0a7ee71a4e76b49e31b75f8622852324d58a4 + 1ba58cf884726dfdf02a7662d52f1befe3f16d44 hash_algorithm sha1 url - https://api.github.com/repos/secondlife/3p-kdu/releases/assets/202118208 + https://api.github.com/repos/secondlife/3p-kdu/releases/assets/208381812 name linux64 @@ -1072,15 +1072,31 @@ creds github hash - 8c475dd9616c7e0e3029cc38aefc1e0ab34d2e73 + e8d693089b9ecd15b6644f13ada7ae7c317944df hash_algorithm sha1 url - https://api.github.com/repos/secondlife/3p-kdu/releases/assets/202118209 + https://api.github.com/repos/secondlife/3p-kdu/releases/assets/208381814 name windows64 + linux + + archive + + creds + github + hash + 85e294becce8b2ac5d2e5e052b0e21ff865d1108 + hash_algorithm + sha1 + url + https://api.github.com/repos/secondlife/3p-kdu/releases/assets/208381806 + + name + linux + license Kakadu @@ -1089,7 +1105,7 @@ copyright Kakadu software version - 8.4.1.11540433907 + 8.4.1.11976899217 name kdu description From 6b0b8ce19639a587311823555d4cabf5a98a4793 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 5 Sep 2025 23:18:14 +0300 Subject: [PATCH 127/145] #4536 Fix clipped setting descriptions --- indra/newview/skins/default/xui/en/floater_settings_debug.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/skins/default/xui/en/floater_settings_debug.xml b/indra/newview/skins/default/xui/en/floater_settings_debug.xml index a93be6a18d6..c40ae3ea064 100644 --- a/indra/newview/skins/default/xui/en/floater_settings_debug.xml +++ b/indra/newview/skins/default/xui/en/floater_settings_debug.xml @@ -66,6 +66,7 @@ visible="false" name="comment_text" follows="left|top" + max_length="1024" width="240" top_delta="20" word_wrap="true" /> From d97cb0f18cd96027bd40ade8323b7e4a5a93a55e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 5 Sep 2025 23:47:38 +0300 Subject: [PATCH 128/145] #4639 Crash at getDimensionsF32 --- indra/llui/lltextbase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index ffaa09fd8cb..3fe0df1848c 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -3765,7 +3765,7 @@ bool LLNormalTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& w { height = 0; width = 0; - if (num_chars > 0) + if (num_chars > 0 && (mStart + first_char >= 0)) { height = mFontHeight; const LLWString &text = getWText(); From 8f43b5b77bf4b526af237217aa184215cb55731b Mon Sep 17 00:00:00 2001 From: Rye Date: Fri, 5 Sep 2025 19:35:22 -0400 Subject: [PATCH 129/145] Fix macos build arch and deploy target due to cmake behavior changes --- indra/cmake/Variables.cmake | 6 ++---- indra/newview/CMakeLists.txt | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 8dc51f6efa0..c637e464fea 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -144,7 +144,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(DARWIN 1) string(REGEX MATCH "-mmacosx-version-min=([^ ]+)" scratch "$ENV{LL_BUILD}") - set(CMAKE_OSX_DEPLOYMENT_TARGET "${CMAKE_MATCH_1}") + set(CMAKE_OSX_DEPLOYMENT_TARGET "${CMAKE_MATCH_1}" CACHE STRING "macOS Deploy Target" FORCE) message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET = '${CMAKE_OSX_DEPLOYMENT_TARGET}'") # Use dwarf symbols for most libraries for compilation speed @@ -184,9 +184,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "") set(CMAKE_XCODE_ATTRIBUTE_DISABLE_MANUAL_TARGET_ORDER_BUILD_WARNING YES) set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_64_TO_32_BIT_CONVERSION NO) - if(NOT DEFINED CMAKE_OSX_ARCHITECTURES) - set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64") - endif() + set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "macOS Build Arch" FORCE) endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # Default deploy grid diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 570c74f1cff..c727d5ae572 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1950,7 +1950,8 @@ elseif (DARWIN) set_target_properties(${VIEWER_BINARY_NAME} PROPERTIES RESOURCE SecondLife.xib - LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -Xlinker -dead_strip -Xlinker -map -Xlinker ${CMAKE_CURRENT_BINARY_DIR}/${VIEWER_BINARY_NAME}.MAP" + #LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -Xlinker -dead_strip -Xlinker -map -Xlinker ${CMAKE_CURRENT_BINARY_DIR}/${VIEWER_BINARY_NAME}.MAP" + LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -Xlinker -dead_strip" ) else (WINDOWS) # Linux From 79e4b7b53dc6aff5c0f81fd4aad63c4086cf4133 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 9 Sep 2025 18:35:18 +0300 Subject: [PATCH 130/145] p#428 'multiple textures' sometimes not present when opening picker for the first time --- indra/newview/lltexturectrl.cpp | 49 ++++++++++++++++++++++++++------- indra/newview/lltexturectrl.h | 3 +- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 2027e958d53..5507ef517a4 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -186,6 +186,7 @@ LLFloaterTexturePicker::LLFloaterTexturePicker( mOnUpdateImageStatsCallback(NULL), mBakeTextureEnabled(false), mLocalTextureEnabled(false), + mNoCopyTextureSelected(false), mInventoryPickType(pick_type) { setTentative(tentative); @@ -263,6 +264,7 @@ void LLFloaterTexturePicker::setImageID(const LLUUID& image_id, bool set_selecti if (set_selection) { + // This is going to cause a callback mInventoryPanel->setSelection(item_id, TAKE_FOCUS_NO); } } @@ -597,7 +599,6 @@ bool LLFloaterTexturePicker::postBuild() refreshInventoryFilter(); mInventoryPanel->setFilterPermMask(mImmediateFilterPermMask); - mInventoryPanel->setSelectCallback(boost::bind(&LLFloaterTexturePicker::onSelectionChange, this, _1, _2)); mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); // Disable auto selecting first filtered item because it takes away @@ -616,8 +617,25 @@ bool LLFloaterTexturePicker::postBuild() if(!mImageAssetID.isNull() || mInventoryPickType == PICK_MATERIAL) { - mInventoryPanel->setSelection(findItemID(mImageAssetID, false), TAKE_FOCUS_NO); + LLViewerInventoryItem* itemp = findInvItem(mImageAssetID, false); + LLUUID item_id; + if (itemp) + { + item_id = itemp->getUUID(); + } + + mInventoryPanel->setSelection(item_id, TAKE_FOCUS_NO); + + if (item_id.notNull() && itemp) + { + if (!itemp->getPermissions().allowCopyBy(gAgent.getID())) + { + mNoCopyTextureSelected = true; + } + } } + // Don't call before setSelection, setSelection will mark view as dirty + mInventoryPanel->setSelectCallback(boost::bind(&LLFloaterTexturePicker::onSelectionChange, this, _1, _2)); } childSetAction("l_add_btn", LLFloaterTexturePicker::onBtnAdd, this); @@ -809,12 +827,12 @@ void LLFloaterTexturePicker::draw() } } -const LLUUID& LLFloaterTexturePicker::findItemID(const LLUUID& asset_id, bool copyable_only, bool ignore_library) +LLViewerInventoryItem* LLFloaterTexturePicker::findInvItem(const LLUUID& asset_id, bool copyable_only, bool ignore_library) const { if (asset_id.isNull()) { // null asset id means, no material or texture assigned - return LLUUID::null; + return nullptr; } LLUUID loockup_id = asset_id; @@ -854,30 +872,41 @@ const LLUUID& LLFloaterTexturePicker::findItemID(const LLUUID& asset_id, bool co // search for copyable version first for (S32 i = 0; i < items.size(); i++) { - LLInventoryItem* itemp = items[i]; + LLViewerInventoryItem* itemp = items[i]; LLPermissions item_permissions = itemp->getPermissions(); if (item_permissions.allowCopyBy(gAgent.getID(), gAgent.getGroupID())) { - if(!ignore_library || !gInventory.isObjectDescendentOf(itemp->getUUID(),gInventory.getLibraryRootFolderID())) + if (!ignore_library || !gInventory.isObjectDescendentOf(itemp->getUUID(), gInventory.getLibraryRootFolderID())) { - return itemp->getUUID(); + return itemp; } } } // otherwise just return first instance, unless copyable requested if (copyable_only) { - return LLUUID::null; + return nullptr; } else { - if(!ignore_library || !gInventory.isObjectDescendentOf(items[0]->getUUID(),gInventory.getLibraryRootFolderID())) + if (!ignore_library || !gInventory.isObjectDescendentOf(items[0]->getUUID(), gInventory.getLibraryRootFolderID())) { - return items[0]->getUUID(); + return items[0]; } } } + return nullptr; +} + +const LLUUID& LLFloaterTexturePicker::findItemID(const LLUUID& asset_id, bool copyable_only, bool ignore_library) const +{ + LLViewerInventoryItem* itemp = findInvItem(asset_id, copyable_only, ignore_library); + if (itemp) + { + return itemp->getUUID(); + } + return LLUUID::null; } diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 79957431b73..467b8d1091a 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -340,7 +340,7 @@ class LLFloaterTexturePicker : public LLFloater void setImageID(const LLUUID& image_asset_id, bool set_selection = true); bool updateImageStats(); // true if within limits const LLUUID& getAssetID() { return mImageAssetID; } - const LLUUID& findItemID(const LLUUID& asset_id, bool copyable_only, bool ignore_library = false); + const LLUUID& findItemID(const LLUUID& asset_id, bool copyable_only, bool ignore_library = false) const; void setCanApplyImmediately(bool b); void setActive(bool active); @@ -397,6 +397,7 @@ class LLFloaterTexturePicker : public LLFloater void refreshLocalList(); void refreshInventoryFilter(); void setImageIDFromItem(const LLInventoryItem* itemp, bool set_selection = true); + LLViewerInventoryItem* findInvItem(const LLUUID& asset_id, bool copyable_only, bool ignore_library = false) const; LLPointer mTexturep; LLPointer mGLTFMaterial; From 175400230869963df7a3f126122ace14456c56cb Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Tue, 9 Sep 2025 22:51:55 +0300 Subject: [PATCH 131/145] Fix build failing due to missing nsis Temporary switch to windows 2022, latest 2025 doesn't have nsis --- .github/workflows/build.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 4bf2af644ae..e4da631dc6e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -42,7 +42,7 @@ jobs: needs: setup strategy: matrix: - runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-latest","macos-15"]') }} + runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-2022","macos-15"]') }} configuration: ${{ fromJson(needs.setup.outputs.configurations) }} runs-on: ${{ matrix.runner }} outputs: @@ -306,7 +306,7 @@ jobs: AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} needs: build - runs-on: windows-latest + runs-on: windows-2022 steps: - name: Sign and package Windows viewer if: env.AZURE_KEY_VAULT_URI && env.AZURE_CERT_NAME && env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET && env.AZURE_TENANT_ID From f98a61be70fe7c73d446213bb143edc4035ddef7 Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Fri, 5 Sep 2025 17:58:46 -0700 Subject: [PATCH 132/145] Improvements found in reviewing mac_arm branch #4629 --- indra/cmake/Variables.cmake | 13 ----- indra/llcommon/llmd5.cpp | 2 +- indra/llkdu/llimagej2ckdu.cpp | 2 +- indra/llwindow/llopenglview-objc.mm | 80 ++++++++++++++--------------- indra/newview/llappviewer.cpp | 2 + 5 files changed, 44 insertions(+), 55 deletions(-) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index c637e464fea..22c2156bb88 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -154,19 +154,6 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL "${CMAKE_MATCH_1}") message(STATUS "CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL = '${CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL}'") - # allow disabling this check by setting LL_SKIP_REQUIRE_SYSROOT either ON as cmake cache var or non-empty as environment var - # set(LL_SKIP_REQUIRE_SYSROOT OFF CACHE BOOL "Skip requirement to set toolchain sysroot ahead of time. Not skipped by default for consistency, but skipping can be useful for selecting alternative xcode versions side by side") - # if("$ENV{LL_SKIP_REQUIRE_SYSROOT}" STREQUAL "" AND NOT ${LL_SKIP_REQUIRE_SYSROOT}) - # string(REGEX MATCHALL "[^ ]+" LL_BUILD_LIST "$ENV{LL_BUILD}") - # list(FIND LL_BUILD_LIST "-iwithsysroot" sysroot_idx) - # if ("${sysroot_idx}" LESS 0) - # message(FATAL_ERROR "Environment variable LL_BUILD must contain '-iwithsysroot'") - # endif () - # math(EXPR sysroot_idx "${sysroot_idx} + 1") - # list(GET LL_BUILD_LIST "${sysroot_idx}" CMAKE_OSX_SYSROOT) - # endif() - # message(STATUS "CMAKE_OSX_SYSROOT = '${CMAKE_OSX_SYSROOT}'") - set(CMAKE_XCODE_ATTRIBUTE_GCC_STRICT_ALIASING NO) set(CMAKE_XCODE_ATTRIBUTE_GCC_FAST_MATH NO) set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS sse4.2) diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp index c806c0ab2e9..c8ca586e7fc 100644 --- a/indra/llcommon/llmd5.cpp +++ b/indra/llcommon/llmd5.cpp @@ -279,7 +279,7 @@ void LLMD5::hex_digest(char* s) const } #if LL_DARWIN -#pragma clang diagnostic push +#pragma clang diagnostic pop #endif std::ostream& operator<<(std::ostream& stream, const LLMD5& context) diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 598455a31ad..7eba9494a62 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -316,7 +316,7 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod // *TODO: This seems to be wrong. The base class should have no idea of // how j2c compression works so no good way of computing what's the byte // range to be used. - mCodeStreamp->set_max_bytes(max_bytes); + mCodeStreamp->set_max_bytes(max_bytes); // If you want to flip or rotate the image for some reason, change // the resolution, or identify a restricted region of interest, this is diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index f3aa164f921..c9a62eedb1c 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -28,7 +28,7 @@ #import "llwindowmacosx-objc.h" #import "llappdelegate-objc.h" -#import +#import extern BOOL gHiDPISupport; @@ -66,16 +66,16 @@ attributedStringInfo getSegments(NSAttributedString *str) segment_standouts seg_standouts; NSRange effectiveRange; NSRange limitRange = NSMakeRange(0, [str length]); - + while (limitRange.length > 0) { NSNumber *attr = [str attribute:NSUnderlineStyleAttributeName atIndex:limitRange.location longestEffectiveRange:&effectiveRange inRange:limitRange]; limitRange = NSMakeRange(NSMaxRange(effectiveRange), NSMaxRange(limitRange) - NSMaxRange(effectiveRange)); - + if (effectiveRange.length <= 0) { effectiveRange.length = 1; } - + if ([attr integerValue] == 2) { seg_lengths.push_back(effectiveRange.length); @@ -98,12 +98,12 @@ @implementation NSScreen (PointConversion) + (NSScreen *)currentScreenForMouseLocation { NSPoint mouseLocation = [NSEvent mouseLocation]; - + NSEnumerator *screenEnumerator = [[NSScreen screens] objectEnumerator]; NSScreen *screen; while ((screen = [screenEnumerator nextObject]) && !NSMouseInRect(mouseLocation, screen.frame, NO)) ; - + return screen; } @@ -131,7 +131,7 @@ - (unsigned long)getVramSize { vram_megabytes = 256; } - + return (unsigned long)vram_megabytes; // return value is in megabytes. } @@ -140,15 +140,15 @@ - (void)viewDidMoveToWindow [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowResized:) name:NSWindowDidResizeNotification object:[self window]]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowWillMiniaturize:) name:NSWindowWillMiniaturizeNotification object:[self window]]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:[self window]]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:[self window]]; @@ -222,7 +222,7 @@ - (id) initWithFrame:(NSRect)frame withSamples:(NSUInteger)samples andVsync:(BOO { [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeURL]]; [self initWithFrame:frame]; - + // Initialize with a default "safe" pixel format that will work with versions dating back to OS X 10.6. // Any specialized pixel formats, i.e. a core profile pixel format, should be initialized through rebuildContextWithFormat. // 10.7 and 10.8 don't really care if we're defining a profile or not. If we don't explicitly request a core or legacy profile, it'll always assume a legacy profile (for compatibility reasons). @@ -240,34 +240,34 @@ - (id) initWithFrame:(NSRect)frame withSamples:(NSUInteger)samples andVsync:(BOO NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core, 0 }; - + NSOpenGLPixelFormat *pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attrs] autorelease]; - + if (pixelFormat == nil) { NSLog(@"Failed to create pixel format!", nil); return nil; } - + NSOpenGLContext *glContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil]; - + if (glContext == nil) { NSLog(@"Failed to create OpenGL context!", nil); return nil; } - + [self setPixelFormat:pixelFormat]; //for retina support [self setWantsBestResolutionOpenGLSurface:gHiDPISupport]; [self setOpenGLContext:glContext]; - + [glContext setView:self]; - + [glContext makeCurrentContext]; - + if (vsync) { GLint value = 1; @@ -291,16 +291,16 @@ - (BOOL) rebuildContext - (BOOL) rebuildContextWithFormat:(NSOpenGLPixelFormat *)format { NSOpenGLContext *ctx = [self openGLContext]; - + [ctx clearDrawable]; [ctx initWithFormat:format shareContext:nil]; - + if (ctx == nil) { NSLog(@"Failed to create OpenGL context!", nil); return false; } - + [self setOpenGLContext:ctx]; [ctx setView:self]; [ctx makeCurrentContext]; @@ -405,9 +405,9 @@ - (void) mouseDragged:(NSEvent *)theEvent float(dev_delta.x), float(dev_delta.y) }; - + callDeltaUpdate(mouseDeltas, 0); - + NSPoint mPoint = [self convertPointToBacking:[theEvent locationInWindow]]; mMousePos[0] = mPoint.x; mMousePos[1] = mPoint.y; @@ -431,7 +431,7 @@ - (void) rightMouseDragged:(NSEvent *)theEvent - (void) otherMouseDragged:(NSEvent *)theEvent { - [self mouseDragged:theEvent]; + [self mouseDragged:theEvent]; } - (void) scrollWheel:(NSEvent *)theEvent @@ -455,7 +455,7 @@ - (void) keyDown:(NSEvent *)theEvent { NativeKeyEventData eventData = extractKeyDataFromKeyEvent(theEvent); eventData.mKeyEvent = NativeKeyEventData::KEYDOWN; - + uint keycode = [theEvent keyCode]; // We must not depend on flagsChange event to detect modifier flags changed, // must depend on the modifire flags in the event parameter. @@ -489,13 +489,13 @@ - (void) keyDown:(NSEvent *)theEvent - (void)flagsChanged:(NSEvent *)theEvent { NativeKeyEventData eventData = extractKeyDataFromModifierEvent(theEvent); - + mModifiers = [theEvent modifierFlags]; callModifier([theEvent modifierFlags]); - + NSInteger mask = 0; switch([theEvent keyCode]) - { + { case kVK_Shift: mask = NSEventModifierFlagShift; break; @@ -506,9 +506,9 @@ - (void)flagsChanged:(NSEvent *)theEvent mask = NSEventModifierFlagControl; break; default: - return; + return; } - + if (mModifiers & mask) { eventData.mKeyEvent = NativeKeyEventData::KEYDOWN; @@ -527,7 +527,7 @@ - (void)flagsChanged:(NSEvent *)theEvent { eventData.mKeyEvent = NativeKeyEventData::KEYUP; callKeyUp(&eventData, [theEvent keyCode], 0); - } + } } - (BOOL) acceptsFirstResponder @@ -539,11 +539,11 @@ - (NSDragOperation) draggingEntered:(id)sender { NSPasteboard *pboard; NSDragOperation sourceDragMask; - + sourceDragMask = [sender draggingSourceOperationMask]; - + pboard = [sender draggingPasteboard]; - + if ([[pboard types] containsObject:NSPasteboardTypeURL]) { if (sourceDragMask & NSDragOperationLink) { @@ -558,7 +558,7 @@ - (NSDragOperation) draggingEntered:(id)sender - (NSDragOperation)draggingUpdated:(id )sender { callHandleDragUpdated(mLastDraggedUrl); - + return NSDragOperationLink; } @@ -612,12 +612,12 @@ - (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replaceme unsigned(selectedRange.location), unsigned(selectedRange.length) }; - + unsigned int replacement[2] = { unsigned(replacementRange.location), unsigned(replacementRange.length) }; - + int string_length = [aString length]; unichar *text = new unichar[string_length]; attributedStringInfo segments; @@ -728,7 +728,7 @@ - (void)insertText:(id)aString replacementRange:(NSRange)replacementRange return; } } - + @try { if (!mHasMarkedText) @@ -741,7 +741,7 @@ - (void)insertText:(id)aString replacementRange:(NSRange)replacementRange resetPreedit(); // We may never get this point since unmarkText may be called before insertText ever gets called once we submit our text. // But just in case... - + for (NSInteger i = 0; i < [aString length]; i++) { handleUnicodeCharacter([aString characterAtIndex:i]); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 9eb0d3fade5..2dabf3355a5 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -5660,6 +5660,8 @@ void LLAppViewer::forceErrorBreakpoint() #else #if defined(LL_X86) || defined(LL_X86_64) asm ("int $3"); +#else + __builtin_trap(); #endif #endif return; From 452c8e0ea40da1de684c80b84ffa9ec712f72ed2 Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 11 Sep 2025 20:54:32 -0400 Subject: [PATCH 133/145] Follow up fixes for Apple Silicon (#4662) * Remove GLM sse flag from cmake that was moved to llpreprocessor.h * Further reduce performance loss of HDR and Sharpening on bandwith-constrained gpu by combining gamma correction into tonemap/sharpening shader passes * Update SSE2NEON to 1.8.0 to fix random render nans * Fix occasional startup crash from LLCachedControl being declared in global scope --- autobuild.xml | 6 +- indra/cmake/00-Common.cmake | 5 +- .../shaders/class1/deferred/CASF.glsl | 19 ++++ .../deferred/postDeferredGammaCorrect.glsl | 4 +- .../class1/deferred/postDeferredTonemap.glsl | 28 ++++- indra/newview/llviewershadermgr.cpp | 105 ++++++++++++++++++ indra/newview/llviewershadermgr.h | 5 + indra/newview/llviewerwindow.cpp | 12 +- indra/newview/pipeline.cpp | 69 ++++++++---- indra/newview/pipeline.h | 2 +- 10 files changed, 217 insertions(+), 38 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index c52fc65176f..d1d2f735aff 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -2343,11 +2343,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - c578c2a7f4355197d0ce8544310bc5e785531018 + e51fb1d24836d897ce90b8a72010635915b959d6 hash_algorithm sha1 url - https://github.com/secondlife/3p-sse2neon/releases/download/v1.7.0-r2/sse2neon-1.7.0-dev0.gc8ad5f1.d20241212-common-12287325635.tar.zst + https://github.com/secondlife/3p-sse2neon/releases/download/v1.8.0/sse2neon-1.8.0-common-17657389472.tar.zst name common @@ -2360,7 +2360,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors copyright Copyright (c) 2015-2024 SSE2NEON Contributors. version - 1.7.0-dev0.gc8ad5f1.d20241212 + 1.8.0 name sse2neon canonical_repo diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 7ca58c7ea0e..99ea22ab4b6 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -34,7 +34,10 @@ add_compile_definitions(BOOST_BIND_GLOBAL_PLACEHOLDERS) # Force enable SSE2 instructions in GLM per the manual # https://github.com/g-truc/glm/blob/master/manual.md#section2_10 -add_compile_definitions(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES=1 GLM_FORCE_SSE2=1 GLM_ENABLE_EXPERIMENTAL=1) +add_compile_definitions(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES=1 GLM_ENABLE_EXPERIMENTAL=1) + +# SSE2NEON throws a pointless warning when compiler optimizations are enabled +add_compile_definitions(SSE2NEON_SUPPRESS_WARNINGS=1) # Configure crash reporting set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds") diff --git a/indra/newview/app_settings/shaders/class1/deferred/CASF.glsl b/indra/newview/app_settings/shaders/class1/deferred/CASF.glsl index 017855325c6..8e12d094431 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/CASF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/CASF.glsl @@ -2545,12 +2545,31 @@ A_STATIC void CasSetup( #endif #ifdef A_GPU + +#ifdef LEGACY_GAMMA +uniform float gamma; + +vec3 legacyGamma(vec3 color) +{ + vec3 c = 1. - clamp(color, vec3(0.), vec3(1.)); + c = 1. - pow(c, vec3(gamma)); // s/b inverted already CPU-side + + return c; +} +#endif + void main() { vec4 diff = vec4(0.f); uvec2 point = uvec2(vary_fragcoord * out_screen_res.xy); CasFilter(diff.r, diff.g, diff.b, point, cas_param_0, cas_param_1, true); diff.a = texture(diffuseRect, vary_fragcoord).a; + diff.rgb = linear_to_srgb(diff.rgb); + +#ifdef LEGACY_GAMMA + diff.rgb = legacyGamma(diff.rgb); +#endif + frag_color = diff; } #endif diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl index 4ccc6f54a8c..d7a47ef8cd2 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl @@ -43,8 +43,6 @@ vec3 legacyGamma(vec3 color) return c; } -vec3 clampHDRRange(vec3 color); - void main() { //this is the one of the rare spots where diffuseRect contains linear color values (not sRGB) @@ -55,7 +53,7 @@ void main() diff.rgb = legacyGamma(diff.rgb); #endif - diff.rgb = clampHDRRange(diff.rgb); + diff.rgb = clamp(diff.rgb, vec3(0.0), vec3(1.0)); frag_color = diff; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl index 1f01c7f16a2..b1218d61aff 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl @@ -31,11 +31,25 @@ uniform sampler2D diffuseRect; in vec2 vary_fragcoord; +#ifdef GAMMA_CORRECT +uniform float gamma; +#endif + vec3 linear_to_srgb(vec3 cl); vec3 toneMap(vec3 color); vec3 clampHDRRange(vec3 color); +#ifdef GAMMA_CORRECT +vec3 legacyGamma(vec3 color) +{ + vec3 c = 1. - clamp(color, vec3(0.), vec3(1.)); + c = 1. - pow(c, vec3(gamma)); // s/b inverted already CPU-side + + return c; +} +#endif + void main() { //this is the one of the rare spots where diffuseRect contains linear color values (not sRGB) @@ -47,8 +61,18 @@ void main() diff.rgb = clamp(diff.rgb, vec3(0.0), vec3(1.0)); #endif - diff.rgb = clampHDRRange(diff.rgb); +#ifdef GAMMA_CORRECT + diff.rgb = linear_to_srgb(diff.rgb); + +#ifdef LEGACY_GAMMA + diff.rgb = legacyGamma(diff.rgb); +#endif + +#endif + + diff.rgb = clamp(diff.rgb, vec3(0.0), vec3(1.0)); // We should always be 0-1 past this point + //debugExposure(diff.rgb); - frag_color = max(diff, vec4(0)); + frag_color = diff; } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index a9c58d5a067..0c912e8dbc5 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -196,6 +196,10 @@ LLGLSLShader gDeferredCoFProgram; LLGLSLShader gDeferredDoFCombineProgram; LLGLSLShader gDeferredPostTonemapProgram; LLGLSLShader gNoPostTonemapProgram; +LLGLSLShader gDeferredPostTonemapGammaCorrectProgram; +LLGLSLShader gNoPostTonemapGammaCorrectProgram; +LLGLSLShader gDeferredPostTonemapLegacyGammaCorrectProgram; +LLGLSLShader gNoPostTonemapLegacyGammaCorrectProgram; LLGLSLShader gDeferredPostGammaCorrectProgram; LLGLSLShader gLegacyPostGammaCorrectProgram; LLGLSLShader gExposureProgram; @@ -206,6 +210,7 @@ LLGLSLShader gSMAAEdgeDetectProgram[4]; LLGLSLShader gSMAABlendWeightsProgram[4]; LLGLSLShader gSMAANeighborhoodBlendProgram[4]; LLGLSLShader gCASProgram; +LLGLSLShader gCASLegacyGammaProgram; LLGLSLShader gDeferredPostNoDoFProgram; LLGLSLShader gDeferredPostNoDoFNoiseProgram; LLGLSLShader gDeferredWLSkyProgram; @@ -443,6 +448,11 @@ void LLViewerShaderMgr::finalizeShaderList() mShaderList.push_back(&gHUDPBRAlphaProgram); mShaderList.push_back(&gDeferredPostTonemapProgram); mShaderList.push_back(&gNoPostTonemapProgram); + mShaderList.push_back(&gDeferredPostTonemapGammaCorrectProgram); + mShaderList.push_back(&gNoPostTonemapGammaCorrectProgram); + mShaderList.push_back(&gDeferredPostTonemapLegacyGammaCorrectProgram); + mShaderList.push_back(&gNoPostTonemapLegacyGammaCorrectProgram); + mShaderList.push_back(&gCASLegacyGammaProgram); mShaderList.push_back(&gDeferredPostGammaCorrectProgram); // for gamma mShaderList.push_back(&gLegacyPostGammaCorrectProgram); mShaderList.push_back(&gDeferredDiffuseProgram); @@ -1116,6 +1126,11 @@ bool LLViewerShaderMgr::loadShadersDeferred() gLegacyPostGammaCorrectProgram.unload(); gDeferredPostTonemapProgram.unload(); gNoPostTonemapProgram.unload(); + gDeferredPostTonemapGammaCorrectProgram.unload(); + gNoPostTonemapGammaCorrectProgram.unload(); + gDeferredPostTonemapLegacyGammaCorrectProgram.unload(); + gNoPostTonemapLegacyGammaCorrectProgram.unload(); + for (auto i = 0; i < 4; ++i) { gFXAAProgram[i].unload(); @@ -1124,6 +1139,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gSMAANeighborhoodBlendProgram[i].unload(); } gCASProgram.unload(); + gCASLegacyGammaProgram.unload(); gEnvironmentMapProgram.unload(); gDeferredWLSkyProgram.unload(); gDeferredWLCloudProgram.unload(); @@ -2486,6 +2502,74 @@ bool LLViewerShaderMgr::loadShadersDeferred() llassert(success); } + if (success) + { + gDeferredPostTonemapGammaCorrectProgram.mName = "Deferred Tonemap Gamma Post Process"; + gDeferredPostTonemapGammaCorrectProgram.mFeatures.hasSrgb = true; + gDeferredPostTonemapGammaCorrectProgram.mFeatures.isDeferred = true; + gDeferredPostTonemapGammaCorrectProgram.mFeatures.hasTonemap = true; + gDeferredPostTonemapGammaCorrectProgram.mShaderFiles.clear(); + gDeferredPostTonemapGammaCorrectProgram.clearPermutations(); + gDeferredPostTonemapGammaCorrectProgram.addPermutation("GAMMA_CORRECT", "1"); + gDeferredPostTonemapGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); + gDeferredPostTonemapGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredTonemap.glsl", GL_FRAGMENT_SHADER)); + gDeferredPostTonemapGammaCorrectProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gDeferredPostTonemapGammaCorrectProgram.createShader(); + llassert(success); + } + + if (success) + { + gNoPostTonemapGammaCorrectProgram.mName = "No Post Tonemap Gamma Post Process"; + gNoPostTonemapGammaCorrectProgram.mFeatures.hasSrgb = true; + gNoPostTonemapGammaCorrectProgram.mFeatures.isDeferred = true; + gNoPostTonemapGammaCorrectProgram.mFeatures.hasTonemap = true; + gNoPostTonemapGammaCorrectProgram.mShaderFiles.clear(); + gNoPostTonemapGammaCorrectProgram.clearPermutations(); + gNoPostTonemapGammaCorrectProgram.addPermutation("GAMMA_CORRECT", "1"); + gNoPostTonemapGammaCorrectProgram.addPermutation("NO_POST", "1"); + gNoPostTonemapGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); + gNoPostTonemapGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredTonemap.glsl", GL_FRAGMENT_SHADER)); + gNoPostTonemapGammaCorrectProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gNoPostTonemapGammaCorrectProgram.createShader(); + llassert(success); + } + + if (success) + { + gDeferredPostTonemapLegacyGammaCorrectProgram.mName = "Deferred Tonemap Legacy Gamma Post Process"; + gDeferredPostTonemapLegacyGammaCorrectProgram.mFeatures.hasSrgb = true; + gDeferredPostTonemapProgram.mFeatures.isDeferred = true; + gDeferredPostTonemapLegacyGammaCorrectProgram.mFeatures.hasTonemap = true; + gDeferredPostTonemapLegacyGammaCorrectProgram.mShaderFiles.clear(); + gDeferredPostTonemapLegacyGammaCorrectProgram.clearPermutations(); + gDeferredPostTonemapLegacyGammaCorrectProgram.addPermutation("GAMMA_CORRECT", "1"); + gDeferredPostTonemapLegacyGammaCorrectProgram.addPermutation("LEGACY_GAMMA", "1"); + gDeferredPostTonemapLegacyGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); + gDeferredPostTonemapLegacyGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredTonemap.glsl", GL_FRAGMENT_SHADER)); + gDeferredPostTonemapLegacyGammaCorrectProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gDeferredPostTonemapLegacyGammaCorrectProgram.createShader(); + llassert(success); + } + + if (success) + { + gNoPostTonemapLegacyGammaCorrectProgram.mName = "No Post Tonemap Legacy Gamma Post Process"; + gNoPostTonemapLegacyGammaCorrectProgram.mFeatures.hasSrgb = true; + gNoPostTonemapLegacyGammaCorrectProgram.mFeatures.isDeferred = true; + gNoPostTonemapLegacyGammaCorrectProgram.mFeatures.hasTonemap = true; + gNoPostTonemapLegacyGammaCorrectProgram.mShaderFiles.clear(); + gNoPostTonemapLegacyGammaCorrectProgram.clearPermutations(); + gNoPostTonemapLegacyGammaCorrectProgram.addPermutation("NO_POST", "1"); + gNoPostTonemapLegacyGammaCorrectProgram.addPermutation("GAMMA_CORRECT", "1"); + gNoPostTonemapLegacyGammaCorrectProgram.addPermutation("LEGACY_GAMMA", "1"); + gNoPostTonemapLegacyGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); + gNoPostTonemapLegacyGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredTonemap.glsl", GL_FRAGMENT_SHADER)); + gNoPostTonemapLegacyGammaCorrectProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gNoPostTonemapLegacyGammaCorrectProgram.createShader(); + llassert(success); + } + if (success && gGLManager.mGLVersion > 3.9f) { std::vector> quality_levels = { {"12", "Low"}, @@ -2669,6 +2753,27 @@ bool LLViewerShaderMgr::loadShadersDeferred() } } + if (success && gGLManager.mGLVersion > 4.05f) + { + gCASLegacyGammaProgram.mName = "Contrast Adaptive Sharpening Legacy Gamma Shader"; + gCASLegacyGammaProgram.mFeatures.hasSrgb = true; + gCASLegacyGammaProgram.mShaderFiles.clear(); + gCASLegacyGammaProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); + gCASLegacyGammaProgram.mShaderFiles.push_back(make_pair("deferred/CASF.glsl", GL_FRAGMENT_SHADER)); + gCASLegacyGammaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gCASLegacyGammaProgram.clearPermutations(); + gCASLegacyGammaProgram.addPermutation("GAMMA_CORRECT", "1"); + gCASLegacyGammaProgram.addPermutation("LEGACY_GAMMA", "1"); + success = gCASLegacyGammaProgram.createShader(); + // llassert(success); + if (!success) + { + LL_WARNS() << "Failed to create shader '" << gCASProgram.mName << "', disabling!" << LL_ENDL; + // continue as if this shader never happened + success = true; + } + } + if (success) { gDeferredPostProgram.mName = "Deferred Post Shader"; diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 7ad2da94640..46da30017db 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -250,12 +250,17 @@ extern LLGLSLShader gSMAAEdgeDetectProgram[4]; extern LLGLSLShader gSMAABlendWeightsProgram[4]; extern LLGLSLShader gSMAANeighborhoodBlendProgram[4]; extern LLGLSLShader gCASProgram; +extern LLGLSLShader gCASLegacyGammaProgram; extern LLGLSLShader gDeferredPostNoDoFProgram; extern LLGLSLShader gDeferredPostNoDoFNoiseProgram; extern LLGLSLShader gDeferredPostGammaCorrectProgram; extern LLGLSLShader gLegacyPostGammaCorrectProgram; extern LLGLSLShader gDeferredPostTonemapProgram; extern LLGLSLShader gNoPostTonemapProgram; +extern LLGLSLShader gDeferredPostTonemapGammaCorrectProgram; +extern LLGLSLShader gNoPostTonemapGammaCorrectProgram; +extern LLGLSLShader gDeferredPostTonemapLegacyGammaCorrectProgram; +extern LLGLSLShader gNoPostTonemapLegacyGammaCorrectProgram; extern LLGLSLShader gExposureProgram; extern LLGLSLShader gExposureProgramNoFade; extern LLGLSLShader gLuminanceProgram; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 70498ecab4c..8abced7e8ff 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -261,9 +261,6 @@ static const F32 MIN_DISPLAY_SCALE = 0.75f; static const char KEY_MOUSELOOK = 'M'; -static LLCachedControl sSnapshotBaseName(LLCachedControl(gSavedPerAccountSettings, "SnapshotBaseName", "Snapshot")); -static LLCachedControl sSnapshotDir(LLCachedControl(gSavedPerAccountSettings, "SnapshotBaseDir", "")); - LLTrace::SampleStatHandle<> LLViewerWindow::sMouseVelocityStat("Mouse Velocity"); @@ -2042,6 +2039,7 @@ LLViewerWindow::LLViewerWindow(const Params& p) std::string LLViewerWindow::getLastSnapshotDir() { + static LLCachedControl sSnapshotDir(LLCachedControl(gSavedPerAccountSettings, "SnapshotBaseDir", "")); return sSnapshotDir; } @@ -4752,6 +4750,7 @@ void LLViewerWindow::saveImageNumbered(LLImageFormatted *image, bool force_picke // Get a base file location if needed. if (force_picker || !isSnapshotLocSet()) { + static LLCachedControl sSnapshotBaseName(LLCachedControl(gSavedPerAccountSettings, "SnapshotBaseName", "Snapshot")); std::string proposed_name(sSnapshotBaseName); // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in. @@ -4850,6 +4849,9 @@ void LLViewerWindow::saveImageLocal(LLImageFormatted *image, const snapshot_save // Shouldn't there be a return here? } + static LLCachedControl sSnapshotBaseName(LLCachedControl(gSavedPerAccountSettings, "SnapshotBaseName", "Snapshot")); + static LLCachedControl sSnapshotDir(LLCachedControl(gSavedPerAccountSettings, "SnapshotBaseDir", "")); + // Look for an unused file name auto is_snapshot_name_loc_set = isSnapshotLocSet(); std::string filepath; @@ -4957,8 +4959,8 @@ void LLViewerWindow::playSnapshotAnimAndSound() bool LLViewerWindow::isSnapshotLocSet() const { - std::string snapshot_dir = sSnapshotDir; - return !snapshot_dir.empty(); + static LLCachedControl sSnapshotDir(LLCachedControl(gSavedPerAccountSettings, "SnapshotBaseDir", "")); + return !sSnapshotDir().empty(); } void LLViewerWindow::resetSnapshotLoc() const diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 6413c08e446..2fe67a5457a 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -7200,7 +7200,7 @@ void LLPipeline::generateExposure(LLRenderTarget* src, LLRenderTarget* dst, bool extern LLPointer gEXRImage; -void LLPipeline::tonemap(LLRenderTarget* src, LLRenderTarget* dst) +void LLPipeline::tonemap(LLRenderTarget* src, LLRenderTarget* dst, bool gamma_correct) { LL_PROFILE_GPU_ZONE("tonemap"); @@ -7218,17 +7218,33 @@ void LLPipeline::tonemap(LLRenderTarget* src, LLRenderTarget* dst) LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); bool no_post = gSnapshotNoPost || psky->getReflectionProbeAmbiance(should_auto_adjust) == 0.f || (buildNoPost && gFloaterTools && gFloaterTools->isAvailable()); - LLGLSLShader& shader = no_post ? gNoPostTonemapProgram : gDeferredPostTonemapProgram; + LLGLSLShader* shader = nullptr; + if(gamma_correct) + { + bool legacy_gamma = psky->getReflectionProbeAmbiance(should_auto_adjust) == 0.f; + if(legacy_gamma) + { + shader = no_post ? &gNoPostTonemapLegacyGammaCorrectProgram : &gDeferredPostTonemapLegacyGammaCorrectProgram; + } + else + { + shader = no_post ? &gNoPostTonemapGammaCorrectProgram : &gDeferredPostTonemapGammaCorrectProgram; + } + } + else + { + shader = no_post ? &gNoPostTonemapProgram : &gDeferredPostTonemapProgram; + } - shader.bind(); + shader->bind(); S32 channel = 0; - shader.bindTexture(LLShaderMgr::DEFERRED_DIFFUSE, src, false, LLTexUnit::TFO_POINT); + shader->bindTexture(LLShaderMgr::DEFERRED_DIFFUSE, src, false, LLTexUnit::TFO_POINT); - shader.bindTexture(LLShaderMgr::EXPOSURE_MAP, &mExposureMap); + shader->bindTexture(LLShaderMgr::EXPOSURE_MAP, &mExposureMap); - shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, (GLfloat)src->getWidth(), (GLfloat)src->getHeight()); + shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, (GLfloat)src->getWidth(), (GLfloat)src->getHeight()); static LLCachedControl exposure(gSavedSettings, "RenderExposure", 1.f); @@ -7238,17 +7254,17 @@ void LLPipeline::tonemap(LLRenderTarget* src, LLRenderTarget* dst) static LLStaticHashedString tonemap_mix("tonemap_mix"); static LLStaticHashedString tonemap_type("tonemap_type"); - shader.uniform1f(s_exposure, e); + shader->uniform1f(s_exposure, e); static LLCachedControl tonemap_type_setting(gSavedSettings, "RenderTonemapType", 0U); - shader.uniform1i(tonemap_type, tonemap_type_setting); - shader.uniform1f(tonemap_mix, psky->getTonemapMix(should_auto_adjust())); + shader->uniform1i(tonemap_type, tonemap_type_setting); + shader->uniform1f(tonemap_mix, psky->getTonemapMix(should_auto_adjust())); mScreenTriangleVB->setBuffer(); mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); gGL.getTexUnit(channel)->unbind(src->getUsage()); - shader.unbind(); + shader->unbind(); } dst->flush(); } @@ -7422,13 +7438,21 @@ void LLPipeline::applyCAS(LLRenderTarget* src, LLRenderTarget* dst) { static LLCachedControl cas_sharpness(gSavedSettings, "RenderCASSharpness", 0.4f); LL_PROFILE_GPU_ZONE("cas"); - if (cas_sharpness == 0.0f || !gCASProgram.isComplete()) + if (cas_sharpness == 0.0f || !gCASProgram.isComplete() || !gCASLegacyGammaProgram.isComplete()) { gPipeline.copyRenderTarget(src, dst); return; } LLGLSLShader* sharpen_shader = &gCASProgram; + static LLCachedControl should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", false); + + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + bool legacy_gamma = psky->getReflectionProbeAmbiance(should_auto_adjust) == 0.f; + if(legacy_gamma) + { + sharpen_shader = &gCASLegacyGammaProgram; + } // Bind setup: dst->bindTarget(); @@ -7990,7 +8014,6 @@ void LLPipeline::renderFinalize() static LLCachedControl has_hdr(gSavedSettings, "RenderHDREnabled", true); bool hdr = gGLManager.mGLVersion > 4.05f && has_hdr(); - LLRenderTarget* postHDRBuffer = &mRT->screen; if (hdr) { copyScreenSpaceReflections(&mRT->screen, &mSceneMap); @@ -7999,21 +8022,21 @@ void LLPipeline::renderFinalize() generateExposure(&mLuminanceMap, &mExposureMap); - tonemap(&mRT->screen, &mRT->deferredLight); - static LLCachedControl cas_sharpness(gSavedSettings, "RenderCASSharpness", 0.4f); - if (cas_sharpness != 0.0f && gCASProgram.isComplete()) - { - applyCAS(&mRT->deferredLight, &mRT->screen); - postHDRBuffer = &mRT->screen; - } - else + bool apply_cas = cas_sharpness != 0.0f && gCASProgram.isComplete() && gCASLegacyGammaProgram.isComplete(); + + tonemap(&mRT->screen, apply_cas ? &mRT->deferredLight : &mPostPingMap, !apply_cas); + + if (apply_cas) { - postHDRBuffer = &mRT->deferredLight; + // Gamma Corrects + applyCAS(&mRT->deferredLight, &mPostPingMap); } } - - gammaCorrect(postHDRBuffer, &mPostPingMap); + else + { + gammaCorrect(&mRT->screen, &mPostPingMap); + } LLVertexBuffer::unbind(); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index b3796a6febc..dff0af46e20 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -155,7 +155,7 @@ class LLPipeline void copyScreenSpaceReflections(LLRenderTarget* src, LLRenderTarget* dst); void generateLuminance(LLRenderTarget* src, LLRenderTarget* dst); void generateExposure(LLRenderTarget* src, LLRenderTarget* dst, bool use_history = true); - void tonemap(LLRenderTarget* src, LLRenderTarget* dst); + void tonemap(LLRenderTarget* src, LLRenderTarget* dst, bool gamma_correct); void gammaCorrect(LLRenderTarget* src, LLRenderTarget* dst); void generateGlow(LLRenderTarget* src); void applyCAS(LLRenderTarget* src, LLRenderTarget* dst); From cf3352e6f24630948c38db52b749a103e4d08d77 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Fri, 12 Sep 2025 15:54:21 +0300 Subject: [PATCH 134/145] #3957 Add indication to a folder's context menu that it is the default upload location --- indra/newview/llinventoryfunctions.cpp | 25 +++++ indra/newview/llinventoryfunctions.h | 1 + indra/newview/llinventorygallerymenu.cpp | 7 ++ indra/newview/llinventorygallerymenu.h | 1 + indra/newview/llinventorypanel.cpp | 8 ++ indra/newview/llinventorypanel.h | 1 + .../default/xui/en/menu_gallery_inventory.xml | 98 +++++++------------ .../skins/default/xui/en/menu_inventory.xml | 45 ++++++--- 8 files changed, 107 insertions(+), 79 deletions(-) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index d1fd82a7f19..e6b33453d51 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -3890,6 +3890,31 @@ void LLInventoryAction::fileUploadLocation(const LLUUID& dest_id, const std::str } } +bool LLInventoryAction::isFileUploadLocation(const LLUUID& dest_id, const std::string& action) +{ + if (action == "def_model") + { + return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_OBJECT) == dest_id; + } + else if (action == "def_texture") + { + return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE) == dest_id; + } + else if (action == "def_sound") + { + return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_SOUND) == dest_id; + } + else if (action == "def_animation") + { + return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_ANIMATION) == dest_id; + } + else if (action == "def_pbr_material") + { + return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL) == dest_id; + } + return false; +} + void LLInventoryAction::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle root) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index ae7bb8770d5..77a2a188773 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -653,6 +653,7 @@ struct LLInventoryAction static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle root); static void removeItemFromDND(LLFolderView* root); static void fileUploadLocation(const LLUUID& dest_id, const std::string& action); + static bool isFileUploadLocation(const LLUUID& dest_id, const std::string& action); static void saveMultipleTextures(const std::vector& filenames, std::set selected_items, LLInventoryModel* model); diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 7212c4dedb4..e129a1296a3 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -110,6 +110,7 @@ LLContextMenu* LLInventoryGalleryContextMenu::createMenu() registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery))); enable_registrar.add("Inventory.CanSetUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::canSetUploadLocation, this, _2)); + enable_registrar.add("Inventory.FileUploadLocation.Check", boost::bind(&LLInventoryGalleryContextMenu::isUploadLocationSelected, this, _2)); enable_registrar.add("Inventory.EnvironmentEnabled", [](LLUICtrl*, const LLSD&) { @@ -489,6 +490,12 @@ void LLInventoryGalleryContextMenu::fileUploadLocation(const LLSD& userdata) LLInventoryAction::fileUploadLocation(mUUIDs.front(), param); } +bool LLInventoryGalleryContextMenu::isUploadLocationSelected(const LLSD& userdata) +{ + const std::string param = userdata.asString(); + return LLInventoryAction::isFileUploadLocation(mUUIDs.front(), param); +} + bool LLInventoryGalleryContextMenu::canSetUploadLocation(const LLSD& userdata) { if (mUUIDs.size() != 1) diff --git a/indra/newview/llinventorygallerymenu.h b/indra/newview/llinventorygallerymenu.h index 7c3545432b1..e90c7a19d25 100644 --- a/indra/newview/llinventorygallerymenu.h +++ b/indra/newview/llinventorygallerymenu.h @@ -47,6 +47,7 @@ class LLInventoryGalleryContextMenu : public LLListContextMenu void updateMenuItemsVisibility(LLContextMenu* menu); void fileUploadLocation(const LLSD& userdata); + bool isUploadLocationSelected(const LLSD& userdata); bool canSetUploadLocation(const LLSD& userdata); static void onRename(const LLSD& notification, const LLSD& response); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 590cbbec4ec..a935ede1860 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -187,6 +187,7 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) : mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this)); mCommitCallbackRegistrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, this)); mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryPanel::fileUploadLocation, this, _2)); + mEnableCallbackRegistrar.add("Inventory.FileUploadLocation.Check", boost::bind(&LLInventoryPanel::isUploadLocationSelected, this, _2)); mCommitCallbackRegistrar.add("Inventory.OpenNewFolderWindow", boost::bind(&LLInventoryPanel::openSingleViewInventory, this, LLUUID())); } @@ -1832,6 +1833,13 @@ void LLInventoryPanel::fileUploadLocation(const LLSD& userdata) LLInventoryAction::fileUploadLocation(dest, param); } +bool LLInventoryPanel::isUploadLocationSelected(const LLSD& userdata) +{ + const std::string param = userdata.asString(); + const LLUUID dest = LLFolderBridge::sSelf.get()->getUUID(); + return LLInventoryAction::isFileUploadLocation(dest, param); +} + void LLInventoryPanel::openSingleViewInventory(LLUUID folder_id) { LLPanelMainInventory::newFolderWindow(folder_id.isNull() ? LLFolderBridge::sSelf.get()->getUUID() : folder_id); diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 473283352ff..50333709fc6 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -225,6 +225,7 @@ class LLInventoryPanel : public LLPanel void doCreate(const LLSD& userdata); bool beginIMSession(); void fileUploadLocation(const LLSD& userdata); + bool isUploadLocationSelected(const LLSD& userdata); void openSingleViewInventory(LLUUID folder_id = LLUUID()); void purgeSelectedItems(); bool attachObject(const LLSD& userdata); diff --git a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml index d8090070bda..3cfe2e0e6ff 100644 --- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml @@ -686,51 +686,6 @@ function="Inventory.DoToSelected" parameter="remove_from_favorites" /> - - - - - - - - - - - - - - - - - - - - - - - + + - - - - + + - - - - + + - - - - + + - - + + - - - - + + - - - + + - - - + + - - - + + - - + + Date: Fri, 12 Sep 2025 19:17:58 -0400 Subject: [PATCH 135/145] Use XL mac runners due to the unibin build time. (#4674) Temporary until we can better parallelize architecture specific builds. --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 8689f2308ec..1e5b4958e17 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -42,7 +42,7 @@ jobs: needs: setup strategy: matrix: - runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-2022","macos-15"]') }} + runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-2022","macos-15-xlarge"]') }} configuration: ${{ fromJson(needs.setup.outputs.configurations) }} runs-on: ${{ matrix.runner }} outputs: From a6d4c1d394eef2cea41f6c6bcd751fec746ec17d Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Fri, 12 Sep 2025 17:07:51 -0700 Subject: [PATCH 136/145] [WebRTC] Rework device handling sequence so that we can handle unplugging/re-plugging devices (#4593) * [WebRTC] Rework device handling sequence so that we can handle unplugging/re-plugging devices The device handling was not processing device updates in the proper sequence as things like AEC use both input and output devices. Devices like headsets are both so unplugging them resulted in various mute conditions and sometimes even a crash. Now, we update both capture and render devices at once in the proper sequence. Test Guidance: * Bring two users in the same place in webrtc regions. * The 'listening' one should have a headset or something set oas 'Default' * Press 'talk' on one, and verify the other can hear. * Unplug the headset from the listening one. * Validate that audio changes from the headset to the speakers. * Plug the headset back in. * Validate that audio changes from speakers to headset. * Do the same type of test with the headset viewer talking. * The microphone used should switch from the headset to the computer (it should have one) Do other various device tests, such as setting devices explicitly, messing with the device selector, etc. * Fix race condition when multiple change device requests might come in at once * Update to m137 The primary feature of this commit is to update libwebrtc from m114 to m137. This is needed to make webrtc buildable, as m114 is not buildable by the current toolset. m137 had some changes to the API, which required renaming or changing namespace of some of the calls. Additionally, this PR moves from a callback mechanism for gathering the energy levels for tuning to a wrapper AudioDeviceModule, which gives us more control over the audio stream. Finally, the new m137-based webrtc has been updated to allow for 192khz audio streams. * Properly pass the observer setting into the inner audio device module * Update to m137 and get rid of some noise This change updates to m137 from m114, which required a few API changes. Additionally, this fixes the hiss that happens shortly after someone unmutes: https://github.com/secondlife/server/issues/2094 There was also an issue with a slight amount of repeated after unmuting if there was audio right before unmuting. This is because the audio processing and buffering still had audio from the previous speaking session. Now, we inject nearly a half second of silence into the audio buffers/processor after unmuting to flush things. * Install nsis on windows * Use the newer digital AGC pipeline m137 improved the AGC pipeline and the existing analog style is going away so move to the new digital pipeline. Also, some tweaking for audio levels so that we don't see inworld bars when tuning, so one's own bars seem a reasonable size, etc. * Install NSIS during windows sisgning and package build step * Try pinning the packaging to windows 2022 to deal with missing nsis * Adjust gain calculation and audio level calculations for tuning and peer connections * Update with mac universal webrtc build * Tuning of voice indicators for both tuning mode and inworld for self. * Redo device deployment to handle cases where multiple deploy requests pile up Also, mute when leaving webrtc-enabled regions or parcels, and unmute when voice comes back. * pre commit issue --- .github/workflows/build.yaml | 1 - autobuild.xml | 14 +- indra/llwebrtc/CMakeLists.txt | 2 +- indra/llwebrtc/llwebrtc.cpp | 740 +++++++++++++++++--------------- indra/llwebrtc/llwebrtc.h | 5 +- indra/llwebrtc/llwebrtc_impl.h | 414 ++++++++++++++---- indra/newview/llvoicewebrtc.cpp | 139 ++++-- indra/newview/llvoicewebrtc.h | 5 - 8 files changed, 831 insertions(+), 489 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1e5b4958e17..42fd44cf9ca 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -93,7 +93,6 @@ jobs: uses: actions/setup-python@v5 with: python-version: "3.11" - - name: Checkout build variables uses: actions/checkout@v4 with: diff --git a/autobuild.xml b/autobuild.xml index d1d2f735aff..c9355c73c04 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -2717,11 +2717,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 6314fdcee81a3538a7d960178ade66301c2fa002 + 43c5f93517794aeade550e4266b959d1f0cfcb7f hash_algorithm sha1 url - https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.73-alpha/webrtc-m114.5735.08.73-alpha.11958809572-darwin64-11958809572.tar.zst + https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-darwin64-17630578914.tar.zst name darwin64 @@ -2731,11 +2731,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 95d7730a3d6955697e043f3fdf20ebdcc0c71fc0 + efc5b176d878cfc16b8f82445d82ddb96815b6ab hash_algorithm sha1 url - https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.73-alpha/webrtc-m114.5735.08.73-alpha.11958809572-linux64-11958809572.tar.zst + https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-linux64-17630578914.tar.zst name linux64 @@ -2745,11 +2745,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - c7b329d6409576af6eb5b80655b007f52639c43b + 1e36f100de32c7c71325497a672fb1659b3f206d hash_algorithm sha1 url - https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.73-alpha/webrtc-m114.5735.08.73-alpha.11958809572-windows64-11958809572.tar.zst + https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-windows64-17630578914.tar.zst name windows64 @@ -2762,7 +2762,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors copyright Copyright (c) 2011, The WebRTC project authors. All rights reserved. version - m114.5735.08.73-alpha.11958809572 + m137.7151.04.20-universal.17630578914 name webrtc vcs_branch diff --git a/indra/llwebrtc/CMakeLists.txt b/indra/llwebrtc/CMakeLists.txt index 4fde489942c..eb10f4eee49 100644 --- a/indra/llwebrtc/CMakeLists.txt +++ b/indra/llwebrtc/CMakeLists.txt @@ -42,7 +42,7 @@ if (WINDOWS) iphlpapi libcmt) # as the webrtc libraries are release, build this binary as release as well. - target_compile_options(llwebrtc PRIVATE "/MT") + target_compile_options(llwebrtc PRIVATE "/MT" "/Zc:wchar_t") if (USE_BUGSPLAT) set_target_properties(llwebrtc PROPERTIES PDB_OUTPUT_DIRECTORY "${SYMBOLS_STAGING_DIR}") endif (USE_BUGSPLAT) diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp index 20951ff8167..edba2bee9ad 100644 --- a/indra/llwebrtc/llwebrtc.cpp +++ b/indra/llwebrtc/llwebrtc.cpp @@ -9,7 +9,7 @@ * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; - * version 2.1 of the License only. + * version 2.1 of the License only * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -32,41 +32,79 @@ #include "api/audio_codecs/audio_encoder_factory.h" #include "api/audio_codecs/builtin_audio_decoder_factory.h" #include "api/audio_codecs/builtin_audio_encoder_factory.h" +#include "api/audio/builtin_audio_processing_builder.h" #include "api/media_stream_interface.h" #include "api/media_stream_track.h" #include "modules/audio_processing/audio_buffer.h" #include "modules/audio_mixer/audio_mixer_impl.h" +#include "api/environment/environment_factory.h" namespace llwebrtc { +#if WEBRTC_WIN +static int16_t PLAYOUT_DEVICE_DEFAULT = webrtc::AudioDeviceModule::kDefaultDevice; +static int16_t RECORD_DEVICE_DEFAULT = webrtc::AudioDeviceModule::kDefaultDevice; +#else +static int16_t PLAYOUT_DEVICE_DEFAULT = 0; +static int16_t RECORD_DEVICE_DEFAULT = 0; +#endif -static int16_t PLAYOUT_DEVICE_DEFAULT = -1; -static int16_t PLAYOUT_DEVICE_BAD = -2; -static int16_t RECORD_DEVICE_DEFAULT = -1; -static int16_t RECORD_DEVICE_BAD = -2; -LLAudioDeviceObserver::LLAudioDeviceObserver() : mSumVector {0}, mMicrophoneEnergy(0.0) {} +// +// LLWebRTCAudioTransport implementation +// -float LLAudioDeviceObserver::getMicrophoneEnergy() { return mMicrophoneEnergy; } +LLWebRTCAudioTransport::LLWebRTCAudioTransport() : mMicrophoneEnergy(0.0) +{ + memset(mSumVector, 0, sizeof(mSumVector)); +} -// TODO: Pull smoothing/filtering code into a common helper function -// for LLAudioDeviceObserver and LLCustomProcessor +void LLWebRTCAudioTransport::SetEngineTransport(webrtc::AudioTransport* t) +{ + engine_.store(t, std::memory_order_release); +} -void LLAudioDeviceObserver::OnCaptureData(const void *audio_samples, - const size_t num_samples, - const size_t bytes_per_sample, - const size_t num_channels, - const uint32_t samples_per_sec) +int32_t LLWebRTCAudioTransport::RecordedDataIsAvailable(const void* audio_data, + size_t number_of_frames, + size_t bytes_per_frame, + size_t number_of_channels, + uint32_t samples_per_sec, + uint32_t total_delay_ms, + int32_t clock_drift, + uint32_t current_mic_level, + bool key_pressed, + uint32_t& new_mic_level) { + auto* engine = engine_.load(std::memory_order_acquire); + + // 1) Deliver to engine (authoritative). + int32_t ret = 0; + if (engine) + { + ret = engine->RecordedDataIsAvailable(audio_data, + number_of_frames, + bytes_per_frame, + number_of_channels, + samples_per_sec, + total_delay_ms, + clock_drift, + current_mic_level, + key_pressed, + new_mic_level); + } + + // 2) Calculate energy for microphone level monitoring // calculate the energy float energy = 0; - const short *samples = (const short *) audio_samples; - for (size_t index = 0; index < num_samples * num_channels; index++) + const short *samples = (const short *) audio_data; + + for (size_t index = 0; index < number_of_frames * number_of_channels; index++) { float sample = (static_cast(samples[index]) / (float) 32767); energy += sample * sample; } - + float gain = mGain.load(std::memory_order_relaxed); + energy = energy * gain * gain; // smooth it. size_t buffer_size = sizeof(mSumVector) / sizeof(mSumVector[0]); float totalSum = 0; @@ -78,18 +116,59 @@ void LLAudioDeviceObserver::OnCaptureData(const void *audio_samples, } mSumVector[i] = energy; totalSum += energy; - mMicrophoneEnergy = std::sqrt(totalSum / (num_samples * buffer_size)); + mMicrophoneEnergy = std::sqrt(totalSum / (number_of_frames * number_of_channels * buffer_size)); + + return ret; } -void LLAudioDeviceObserver::OnRenderData(const void *audio_samples, - const size_t num_samples, - const size_t bytes_per_sample, - const size_t num_channels, - const uint32_t samples_per_sec) +int32_t LLWebRTCAudioTransport::NeedMorePlayData(size_t number_of_frames, + size_t bytes_per_frame, + size_t number_of_channels, + uint32_t samples_per_sec, + void* audio_data, + size_t& number_of_samples_out, + int64_t* elapsed_time_ms, + int64_t* ntp_time_ms) { + auto* engine = engine_.load(std::memory_order_acquire); + if (!engine) + { + // No engine sink; output silence to be safe. + const size_t bytes = number_of_frames * bytes_per_frame * number_of_channels; + memset(audio_data, 0, bytes); + number_of_samples_out = bytes_per_frame; + return 0; + } + + // Only the engine should fill the buffer. + return engine->NeedMorePlayData(number_of_frames, + bytes_per_frame, + number_of_channels, + samples_per_sec, + audio_data, + number_of_samples_out, + elapsed_time_ms, + ntp_time_ms); } -LLCustomProcessor::LLCustomProcessor() : mSampleRateHz(0), mNumChannels(0), mMicrophoneEnergy(0.0), mGain(1.0) +void LLWebRTCAudioTransport::PullRenderData(int bits_per_sample, + int sample_rate, + size_t number_of_channels, + size_t number_of_frames, + void* audio_data, + int64_t* elapsed_time_ms, + int64_t* ntp_time_ms) +{ + auto* engine = engine_.load(std::memory_order_acquire); + + if (engine) + { + engine + ->PullRenderData(bits_per_sample, sample_rate, number_of_channels, number_of_frames, audio_data, elapsed_time_ms, ntp_time_ms); + } +} + +LLCustomProcessor::LLCustomProcessor(LLCustomProcessorStatePtr state) : mSampleRateHz(0), mNumChannels(0), mState(state) { memset(mSumVector, 0, sizeof(mSumVector)); } @@ -101,40 +180,61 @@ void LLCustomProcessor::Initialize(int sample_rate_hz, int num_channels) memset(mSumVector, 0, sizeof(mSumVector)); } -void LLCustomProcessor::Process(webrtc::AudioBuffer *audio_in) +void LLCustomProcessor::Process(webrtc::AudioBuffer *audio) { - webrtc::StreamConfig stream_config; - stream_config.set_sample_rate_hz(mSampleRateHz); - stream_config.set_num_channels(mNumChannels); - std::vector frame; - std::vector frame_samples; - - if (audio_in->num_channels() < 1 || audio_in->num_frames() < 480) + if (audio->num_channels() < 1 || audio->num_frames() < 480) { return; } - // grab the input audio - frame_samples.resize(stream_config.num_samples()); - frame.resize(stream_config.num_channels()); - for (size_t ch = 0; ch < stream_config.num_channels(); ++ch) + // calculate the energy + + float desired_gain = mState->getGain(); + if (mState->getDirty()) { - frame[ch] = &(frame_samples)[ch * stream_config.num_frames()]; + // We'll delay ramping by 30ms in order to clear out buffers that may + // have had content before muting. And for the last 20ms, we'll ramp + // down or up smoothly. + mRampFrames = 5; + + // we've changed our desired gain, so set the incremental + // gain change so that we smoothly step over 20ms + mGainStep = (desired_gain - mCurrentGain) / (mSampleRateHz / 50); } - audio_in->CopyTo(stream_config, &frame[0]); - - // calculate the energy - float energy = 0; - for (size_t index = 0; index < stream_config.num_samples(); index++) + if (mRampFrames) { - float sample = frame_samples[index]; - sample = sample * mGain; // apply gain - frame_samples[index] = sample; // write processed sample back to buffer. - energy += sample * sample; + if (mRampFrames-- > 2) + { + // don't change the gain if we're still in the 'don't move' phase + mGainStep = 0.0f; + } + } + else + { + // We've ramped all the way down, so don't step the gain any more and + // just maintaint he current gain. + mGainStep = 0.0f; + mCurrentGain = desired_gain; } - audio_in->CopyFrom(&frame[0], stream_config); + float energy = 0; + + auto chans = audio->channels(); + for (size_t ch = 0; ch < audio->num_channels(); ch++) + { + float* frame_samples = chans[ch]; + float gain = mCurrentGain; + for (size_t index = 0; index < audio->num_frames(); index++) + { + float sample = frame_samples[index]; + sample = sample * gain; // apply gain + frame_samples[index] = sample; // write processed sample back to buffer. + energy += sample * sample; + gain += mGainStep; + } + } + mCurrentGain += audio->num_frames() * mGainStep; // smooth it. size_t buffer_size = sizeof(mSumVector) / sizeof(mSumVector[0]); @@ -147,7 +247,7 @@ void LLCustomProcessor::Process(webrtc::AudioBuffer *audio_in) } mSumVector[i] = energy; totalSum += energy; - mMicrophoneEnergy = std::sqrt(totalSum / (stream_config.num_samples() * buffer_size)); + mState->setMicrophoneEnergy(std::sqrt(totalSum / (audio->num_channels() * audio->num_frames() * buffer_size))); } // @@ -159,89 +259,54 @@ LLWebRTCImpl::LLWebRTCImpl(LLWebRTCLogCallback* logCallback) : mPeerCustomProcessor(nullptr), mMute(true), mTuningMode(false), - mPlayoutDevice(0), - mRecordingDevice(0), - mTuningAudioDeviceObserver(nullptr) + mDevicesDeploying(0), + mGain(0.0f) { } void LLWebRTCImpl::init() { - mPlayoutDevice = 0; - mRecordingDevice = 0; - rtc::InitializeSSL(); + webrtc::InitializeSSL(); // Normal logging is rather spammy, so turn it off. - rtc::LogMessage::LogToDebug(rtc::LS_NONE); - rtc::LogMessage::SetLogToStderr(true); - rtc::LogMessage::AddLogToStream(mLogSink, rtc::LS_VERBOSE); + webrtc::LogMessage::LogToDebug(webrtc::LS_NONE); + webrtc::LogMessage::SetLogToStderr(true); + webrtc::LogMessage::AddLogToStream(mLogSink, webrtc::LS_VERBOSE); mTaskQueueFactory = webrtc::CreateDefaultTaskQueueFactory(); // Create the native threads. - mNetworkThread = rtc::Thread::CreateWithSocketServer(); + mNetworkThread = webrtc::Thread::CreateWithSocketServer(); mNetworkThread->SetName("WebRTCNetworkThread", nullptr); mNetworkThread->Start(); - mWorkerThread = rtc::Thread::Create(); + mWorkerThread = webrtc::Thread::Create(); mWorkerThread->SetName("WebRTCWorkerThread", nullptr); mWorkerThread->Start(); - mSignalingThread = rtc::Thread::Create(); + mSignalingThread = webrtc::Thread::Create(); mSignalingThread->SetName("WebRTCSignalingThread", nullptr); mSignalingThread->Start(); - mTuningAudioDeviceObserver = new LLAudioDeviceObserver; - mWorkerThread->PostTask( - [this]() - { - // Initialize the audio devices on the Worker Thread - mTuningDeviceModule = - webrtc::CreateAudioDeviceWithDataObserver(webrtc::AudioDeviceModule::AudioLayer::kPlatformDefaultAudio, - mTaskQueueFactory.get(), - std::unique_ptr(mTuningAudioDeviceObserver)); - - mTuningDeviceModule->Init(); - mTuningDeviceModule->SetPlayoutDevice(mPlayoutDevice); - mTuningDeviceModule->SetRecordingDevice(mRecordingDevice); - mTuningDeviceModule->EnableBuiltInAEC(false); - mTuningDeviceModule->SetAudioDeviceSink(this); - mTuningDeviceModule->InitMicrophone(); - mTuningDeviceModule->InitSpeaker(); - mTuningDeviceModule->SetStereoRecording(false); - mTuningDeviceModule->SetStereoPlayout(true); - mTuningDeviceModule->InitRecording(); - mTuningDeviceModule->InitPlayout(); - updateDevices(); - }); - mWorkerThread->BlockingCall( [this]() { - // the peer device module doesn't need an observer - // as we pull peer data after audio processing. - mPeerDeviceModule = webrtc::CreateAudioDeviceWithDataObserver(webrtc::AudioDeviceModule::AudioLayer::kPlatformDefaultAudio, - mTaskQueueFactory.get(), - nullptr); - mPeerDeviceModule->Init(); - mPeerDeviceModule->SetPlayoutDevice(mPlayoutDevice); - mPeerDeviceModule->SetRecordingDevice(mRecordingDevice); - mPeerDeviceModule->EnableBuiltInAEC(false); - mPeerDeviceModule->InitMicrophone(); - mPeerDeviceModule->InitSpeaker(); + webrtc::scoped_refptr realADM = + webrtc::AudioDeviceModule::Create(webrtc::AudioDeviceModule::AudioLayer::kPlatformDefaultAudio, mTaskQueueFactory.get()); + mDeviceModule = webrtc::make_ref_counted(realADM); + mDeviceModule->SetObserver(this); }); // The custom processor allows us to retrieve audio data (and levels) // from after other audio processing such as AEC, AGC, etc. - mPeerCustomProcessor = new LLCustomProcessor; - webrtc::AudioProcessingBuilder apb; - apb.SetCapturePostProcessing(std::unique_ptr(mPeerCustomProcessor)); - mAudioProcessingModule = apb.Create(); + mPeerCustomProcessor = std::make_shared(); + webrtc::BuiltinAudioProcessingBuilder apb; + apb.SetCapturePostProcessing(std::make_unique(mPeerCustomProcessor)); + mAudioProcessingModule = apb.Build(webrtc::CreateEnvironment()); webrtc::AudioProcessing::Config apm_config; apm_config.echo_canceller.enabled = false; apm_config.echo_canceller.mobile_mode = false; apm_config.gain_controller1.enabled = false; - apm_config.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::kAdaptiveAnalog; - apm_config.gain_controller2.enabled = false; + apm_config.gain_controller2.enabled = true; apm_config.high_pass_filter.enabled = true; apm_config.noise_suppression.enabled = true; apm_config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kVeryHigh; @@ -252,6 +317,7 @@ void LLWebRTCImpl::init() mAudioProcessingModule->ApplyConfig(apm_config); webrtc::ProcessingConfig processing_config; + processing_config.input_stream().set_num_channels(2); processing_config.input_stream().set_sample_rate_hz(48000); processing_config.output_stream().set_num_channels(2); @@ -266,13 +332,19 @@ void LLWebRTCImpl::init() mPeerConnectionFactory = webrtc::CreatePeerConnectionFactory(mNetworkThread.get(), mWorkerThread.get(), mSignalingThread.get(), - mPeerDeviceModule, + mDeviceModule, webrtc::CreateBuiltinAudioEncoderFactory(), webrtc::CreateBuiltinAudioDecoderFactory(), nullptr /* video_encoder_factory */, nullptr /* video_decoder_factory */, nullptr /* audio_mixer */, mAudioProcessingModule); + mWorkerThread->PostTask( + [this]() + { + mDeviceModule->EnableBuiltInAEC(false); + updateDevices(); + }); } @@ -294,64 +366,16 @@ void LLWebRTCImpl::terminate() mWorkerThread->BlockingCall( [this]() { - if (mTuningDeviceModule) - { - mTuningDeviceModule->StopRecording(); - mTuningDeviceModule->Terminate(); - } - if (mPeerDeviceModule) + if (mDeviceModule) { - mPeerDeviceModule->StopRecording(); - mPeerDeviceModule->Terminate(); - } - mTuningDeviceModule = nullptr; - mPeerDeviceModule = nullptr; - mTaskQueueFactory = nullptr; - }); - rtc::LogMessage::RemoveLogToStream(mLogSink); -} - -// -// Devices functions -// -// Most device-related functionality needs to happen -// on the worker thread (the audio thread,) so those calls will be -// proxied over to that thread. -// -void LLWebRTCImpl::setRecording(bool recording) -{ - mWorkerThread->PostTask( - [this, recording]() - { - if (recording) - { - mPeerDeviceModule->SetStereoRecording(false); - mPeerDeviceModule->InitRecording(); - mPeerDeviceModule->StartRecording(); - } - else - { - mPeerDeviceModule->StopRecording(); - } - }); -} - -void LLWebRTCImpl::setPlayout(bool playing) -{ - mWorkerThread->PostTask( - [this, playing]() - { - if (playing) - { - mPeerDeviceModule->SetStereoPlayout(true); - mPeerDeviceModule->InitPlayout(); - mPeerDeviceModule->StartPlayout(); - } - else - { - mPeerDeviceModule->StopPlayout(); + mDeviceModule->StopRecording(); + mDeviceModule->StopPlayout(); + mDeviceModule->Terminate(); } + mDeviceModule = nullptr; + mTaskQueueFactory = nullptr; }); + webrtc::LogMessage::RemoveLogToStream(mLogSink); } void LLWebRTCImpl::setAudioConfig(LLWebRTCDeviceInterface::AudioConfig config) @@ -359,9 +383,9 @@ void LLWebRTCImpl::setAudioConfig(LLWebRTCDeviceInterface::AudioConfig config) webrtc::AudioProcessing::Config apm_config; apm_config.echo_canceller.enabled = config.mEchoCancellation; apm_config.echo_canceller.mobile_mode = false; - apm_config.gain_controller1.enabled = config.mAGC; - apm_config.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::kAdaptiveAnalog; - apm_config.gain_controller2.enabled = false; + apm_config.gain_controller1.enabled = false; + apm_config.gain_controller2.enabled = config.mAGC; + apm_config.gain_controller2.adaptive_digital.enabled = true; // auto-level speech apm_config.high_pass_filter.enabled = true; apm_config.transient_suppression.enabled = true; apm_config.pipeline.multi_channel_render = true; @@ -414,142 +438,134 @@ void LLWebRTCImpl::unsetDevicesObserver(LLWebRTCDevicesObserver *observer) } } -void ll_set_device_module_capture_device(rtc::scoped_refptr device_module, int16_t device) +// must be run in the worker thread. +void LLWebRTCImpl::workerDeployDevices() { + int16_t recordingDevice = RECORD_DEVICE_DEFAULT; #if WEBRTC_WIN - if (device < 0) - { - device_module->SetRecordingDevice(webrtc::AudioDeviceModule::kDefaultDevice); - } - else - { - device_module->SetRecordingDevice(device); - } + int16_t recording_device_start = 0; #else - // passed in default is -1, but the device list - // has it at 0 - device_module->SetRecordingDevice(device + 1); + int16_t recording_device_start = 1; #endif - device_module->InitMicrophone(); -} -void LLWebRTCImpl::setCaptureDevice(const std::string &id) -{ - int16_t recordingDevice = RECORD_DEVICE_DEFAULT; - if (id != "Default") + if (mRecordingDevice != "Default") { - for (int16_t i = 0; i < mRecordingDeviceList.size(); i++) + for (int16_t i = recording_device_start; i < mRecordingDeviceList.size(); i++) { - if (mRecordingDeviceList[i].mID == id) + if (mRecordingDeviceList[i].mID == mRecordingDevice) { recordingDevice = i; break; } } } - if (recordingDevice == mRecordingDevice) - { - return; - } - mRecordingDevice = recordingDevice; - if (mTuningMode) - { - mWorkerThread->PostTask([this, recordingDevice]() - { - ll_set_device_module_capture_device(mTuningDeviceModule, recordingDevice); - }); - } - else - { - mWorkerThread->PostTask([this, recordingDevice]() - { - bool recording = mPeerDeviceModule->Recording(); - if (recording) - { - mPeerDeviceModule->StopRecording(); - } - ll_set_device_module_capture_device(mPeerDeviceModule, recordingDevice); - if (recording) - { - mPeerDeviceModule->SetStereoRecording(false); - mPeerDeviceModule->InitRecording(); - mPeerDeviceModule->StartRecording(); - } - }); - } -} - -void ll_set_device_module_render_device(rtc::scoped_refptr device_module, int16_t device) -{ + mDeviceModule->StopPlayout(); + mDeviceModule->ForceStopRecording(); #if WEBRTC_WIN - if (device < 0) + if (recordingDevice < 0) { - device_module->SetPlayoutDevice(webrtc::AudioDeviceModule::kDefaultDevice); + mDeviceModule->SetRecordingDevice((webrtc::AudioDeviceModule::WindowsDeviceType)recordingDevice); } else { - device_module->SetPlayoutDevice(device); + mDeviceModule->SetRecordingDevice(recordingDevice); } #else - device_module->SetPlayoutDevice(device + 1); + mDeviceModule->SetRecordingDevice(recordingDevice); #endif - device_module->InitSpeaker(); -} + mDeviceModule->InitMicrophone(); + mDeviceModule->SetStereoRecording(false); + mDeviceModule->InitRecording(); -void LLWebRTCImpl::setRenderDevice(const std::string &id) -{ int16_t playoutDevice = PLAYOUT_DEVICE_DEFAULT; - if (id != "Default") +#if WEBRTC_WIN + int16_t playout_device_start = 0; +#else + int16_t playout_device_start = 1; +#endif + if (mPlayoutDevice != "Default") { - for (int16_t i = 0; i < mPlayoutDeviceList.size(); i++) + for (int16_t i = playout_device_start; i < mPlayoutDeviceList.size(); i++) { - if (mPlayoutDeviceList[i].mID == id) + if (mPlayoutDeviceList[i].mID == mPlayoutDevice) { playoutDevice = i; break; } } } - if (playoutDevice == mPlayoutDevice) + +#if WEBRTC_WIN + if (playoutDevice < 0) { - return; + mDeviceModule->SetPlayoutDevice((webrtc::AudioDeviceModule::WindowsDeviceType)playoutDevice); + } + else + { + mDeviceModule->SetPlayoutDevice(playoutDevice); } - mPlayoutDevice = playoutDevice; +#else + mDeviceModule->SetPlayoutDevice(playoutDevice); +#endif + mDeviceModule->InitSpeaker(); + mDeviceModule->SetStereoPlayout(true); + mDeviceModule->InitPlayout(); - if (mTuningMode) + if ((!mMute && mPeerConnections.size()) || mTuningMode) { - mWorkerThread->PostTask( - [this, playoutDevice]() - { - ll_set_device_module_render_device(mTuningDeviceModule, playoutDevice); - }); + mDeviceModule->ForceStartRecording(); } - else + + if (!mTuningMode) { - mWorkerThread->PostTask( - [this, playoutDevice]() + mDeviceModule->StartPlayout(); + } + mSignalingThread->PostTask( + [this] + { + for (auto& connection : mPeerConnections) { - bool playing = mPeerDeviceModule->Playing(); - if (playing) + if (mTuningMode) { - mPeerDeviceModule->StopPlayout(); + connection->enableSenderTracks(false); } - ll_set_device_module_render_device(mPeerDeviceModule, playoutDevice); - if (playing) + else { - mPeerDeviceModule->SetStereoPlayout(true); - mPeerDeviceModule->InitPlayout(); - mPeerDeviceModule->StartPlayout(); + connection->resetMute(); } - }); + connection->enableReceiverTracks(!mTuningMode); + } + if (1 < mDevicesDeploying.fetch_sub(1, std::memory_order_relaxed)) + { + mWorkerThread->PostTask([this] { workerDeployDevices(); }); + } + }); +} + +void LLWebRTCImpl::setCaptureDevice(const std::string &id) +{ + + if (mRecordingDevice != id) + { + mRecordingDevice = id; + deployDevices(); + } +} + +void LLWebRTCImpl::setRenderDevice(const std::string &id) +{ + if (mPlayoutDevice != id) + { + mPlayoutDevice = id; + deployDevices(); } } // updateDevices needs to happen on the worker thread. void LLWebRTCImpl::updateDevices() { - int16_t renderDeviceCount = mTuningDeviceModule->PlayoutDevices(); + int16_t renderDeviceCount = mDeviceModule->PlayoutDevices(); mPlayoutDeviceList.clear(); #if WEBRTC_WIN @@ -563,11 +579,11 @@ void LLWebRTCImpl::updateDevices() { char name[webrtc::kAdmMaxDeviceNameSize]; char guid[webrtc::kAdmMaxGuidSize]; - mTuningDeviceModule->PlayoutDeviceName(index, name, guid); + mDeviceModule->PlayoutDeviceName(index, name, guid); mPlayoutDeviceList.emplace_back(name, guid); } - int16_t captureDeviceCount = mTuningDeviceModule->RecordingDevices(); + int16_t captureDeviceCount = mDeviceModule->RecordingDevices(); mRecordingDeviceList.clear(); #if WEBRTC_WIN @@ -581,7 +597,7 @@ void LLWebRTCImpl::updateDevices() { char name[webrtc::kAdmMaxDeviceNameSize]; char guid[webrtc::kAdmMaxGuidSize]; - mTuningDeviceModule->RecordingDeviceName(index, name, guid); + mDeviceModule->RecordingDeviceName(index, name, guid); mRecordingDeviceList.emplace_back(name, guid); } @@ -593,11 +609,7 @@ void LLWebRTCImpl::updateDevices() void LLWebRTCImpl::OnDevicesUpdated() { - // reset these to a bad value so an update is forced - mRecordingDevice = RECORD_DEVICE_BAD; - mPlayoutDevice = PLAYOUT_DEVICE_BAD; - - updateDevices(); + deployDevices(); } @@ -605,60 +617,109 @@ void LLWebRTCImpl::setTuningMode(bool enable) { mTuningMode = enable; mWorkerThread->PostTask( - [this, enable] { - if (enable) - { - mPeerDeviceModule->StopRecording(); - mPeerDeviceModule->StopPlayout(); - ll_set_device_module_render_device(mTuningDeviceModule, mPlayoutDevice); - ll_set_device_module_capture_device(mTuningDeviceModule, mRecordingDevice); - mTuningDeviceModule->InitPlayout(); - mTuningDeviceModule->InitRecording(); - mTuningDeviceModule->StartRecording(); - // TODO: Starting Playout on the TDM appears to create an audio artifact (click) - // in this case, so disabling it for now. We may have to do something different - // if we enable 'echo playback' via the TDM when tuning. - //mTuningDeviceModule->StartPlayout(); - } - else - { - mTuningDeviceModule->StopRecording(); - //mTuningDeviceModule->StopPlayout(); - ll_set_device_module_render_device(mPeerDeviceModule, mPlayoutDevice); - ll_set_device_module_capture_device(mPeerDeviceModule, mRecordingDevice); - mPeerDeviceModule->SetStereoPlayout(true); - mPeerDeviceModule->SetStereoRecording(false); - mPeerDeviceModule->InitPlayout(); - mPeerDeviceModule->InitRecording(); - mPeerDeviceModule->StartPlayout(); - mPeerDeviceModule->StartRecording(); - } - } - ); - mSignalingThread->PostTask( - [this, enable] + [this] { - for (auto &connection : mPeerConnections) - { - if (enable) + mDeviceModule->SetTuning(mTuningMode, mMute); + mSignalingThread->PostTask( + [this] { - connection->enableSenderTracks(false); - } - else - { - connection->resetMute(); - } - connection->enableReceiverTracks(!enable); - } + for (auto& connection : mPeerConnections) + { + if (mTuningMode) + { + connection->enableSenderTracks(false); + } + else + { + connection->resetMute(); + } + connection->enableReceiverTracks(!mTuningMode); + } + }); + }); +} + +void LLWebRTCImpl::deployDevices() +{ + if (0 < mDevicesDeploying.fetch_add(1, std::memory_order_relaxed)) + { + return; + } + mWorkerThread->PostTask( + [this] { + workerDeployDevices(); }); } -float LLWebRTCImpl::getTuningAudioLevel() { return -20 * log10f(mTuningAudioDeviceObserver->getMicrophoneEnergy()); } +float LLWebRTCImpl::getTuningAudioLevel() +{ + return mDeviceModule ? -20 * log10f(mDeviceModule->GetMicrophoneEnergy()) : std::numeric_limits::infinity(); +} -float LLWebRTCImpl::getPeerConnectionAudioLevel() { return -20 * log10f(mPeerCustomProcessor->getMicrophoneEnergy()); } +void LLWebRTCImpl::setTuningMicGain(float gain) +{ + if (mTuningMode && mDeviceModule) + { + mDeviceModule->SetTuningMicGain(gain); + } +} + +float LLWebRTCImpl::getPeerConnectionAudioLevel() +{ + return mTuningMode ? std::numeric_limits::infinity() + : (mPeerCustomProcessor ? -20 * log10f(mPeerCustomProcessor->getMicrophoneEnergy()) + : std::numeric_limits::infinity()); +} -void LLWebRTCImpl::setPeerConnectionGain(float gain) { mPeerCustomProcessor->setGain(gain); } +void LLWebRTCImpl::setMicGain(float gain) +{ + mGain = gain; + if (!mTuningMode && mPeerCustomProcessor) + { + mPeerCustomProcessor->setGain(gain); + } +} +void LLWebRTCImpl::setMute(bool mute, int delay_ms) +{ + if (mMute != mute) + { + mMute = mute; + intSetMute(mute, delay_ms); + } +} + +void LLWebRTCImpl::intSetMute(bool mute, int delay_ms) +{ + if (mPeerCustomProcessor) + { + mPeerCustomProcessor->setGain(mMute ? 0.0f : mGain); + } + if (mMute) + { + mWorkerThread->PostDelayedTask( + [this] + { + if (mDeviceModule) + { + mDeviceModule->ForceStopRecording(); + } + }, + webrtc::TimeDelta::Millis(delay_ms)); + } + else + { + mWorkerThread->PostTask( + [this] + { + if (mDeviceModule) + { + mDeviceModule->InitRecording(); + mDeviceModule->ForceStartRecording(); + } + }); + } +} // // Peer Connection Helpers @@ -666,34 +727,31 @@ void LLWebRTCImpl::setPeerConnectionGain(float gain) { mPeerCustomProcessor->set LLWebRTCPeerConnectionInterface *LLWebRTCImpl::newPeerConnection() { - rtc::scoped_refptr peerConnection = rtc::scoped_refptr(new rtc::RefCountedObject()); + bool empty = mPeerConnections.empty(); + webrtc::scoped_refptr peerConnection = webrtc::scoped_refptr(new webrtc::RefCountedObject()); peerConnection->init(this); - - mPeerConnections.emplace_back(peerConnection); - // Should it really start disabled? - // Seems like something doesn't get the memo and senders need to be reset later - // to remove the voice indicator from taskbar - peerConnection->enableSenderTracks(false); if (mPeerConnections.empty()) { - setRecording(true); - setPlayout(true); + intSetMute(mMute); } + mPeerConnections.emplace_back(peerConnection); + + peerConnection->enableSenderTracks(false); + peerConnection->resetMute(); return peerConnection.get(); } void LLWebRTCImpl::freePeerConnection(LLWebRTCPeerConnectionInterface* peer_connection) { - std::vector>::iterator it = + std::vector>::iterator it = std::find(mPeerConnections.begin(), mPeerConnections.end(), peer_connection); if (it != mPeerConnections.end()) { mPeerConnections.erase(it); - } - if (mPeerConnections.empty()) - { - setRecording(false); - setPlayout(false); + if (mPeerConnections.empty()) + { + intSetMute(true); + } } } @@ -729,7 +787,7 @@ void LLWebRTCPeerConnectionImpl::init(LLWebRTCImpl * webrtc_impl) } void LLWebRTCPeerConnectionImpl::terminate() { - mWebRTCImpl->SignalingBlockingCall( + mWebRTCImpl->PostSignalingTask( [this]() { if (mPeerConnection) @@ -753,7 +811,6 @@ void LLWebRTCPeerConnectionImpl::terminate() track->set_enabled(false); } } - mPeerConnection->SetAudioRecording(false); mPeerConnection->Close(); if (mLocalStream) @@ -840,7 +897,7 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection(const LLWebRTCPeerConnecti mDataChannel->RegisterObserver(this); } - cricket::AudioOptions audioOptions; + webrtc::AudioOptions audioOptions; audioOptions.auto_gain_control = true; audioOptions.echo_cancellation = true; audioOptions.noise_suppression = true; @@ -848,7 +905,7 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection(const LLWebRTCPeerConnecti mLocalStream = mPeerConnectionFactory->CreateLocalMediaStream("SLStream"); - rtc::scoped_refptr audio_track( + webrtc::scoped_refptr audio_track( mPeerConnectionFactory->CreateAudioTrack("SLAudio", mPeerConnectionFactory->CreateAudioSource(audioOptions).get())); audio_track->set_enabled(false); mLocalStream->AddTrack(audio_track); @@ -862,7 +919,7 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection(const LLWebRTCPeerConnecti webrtc::RtpParameters params; webrtc::RtpCodecParameters codecparam; codecparam.name = "opus"; - codecparam.kind = cricket::MEDIA_TYPE_AUDIO; + codecparam.kind = webrtc::MediaType::AUDIO; codecparam.clock_rate = 48000; codecparam.num_channels = 2; codecparam.parameters["stereo"] = "1"; @@ -877,7 +934,7 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection(const LLWebRTCPeerConnecti webrtc::RtpParameters params; webrtc::RtpCodecParameters codecparam; codecparam.name = "opus"; - codecparam.kind = cricket::MEDIA_TYPE_AUDIO; + codecparam.kind = webrtc::MediaType::AUDIO; codecparam.clock_rate = 48000; codecparam.num_channels = 2; codecparam.parameters["stereo"] = "1"; @@ -904,7 +961,6 @@ void LLWebRTCPeerConnectionImpl::enableSenderTracks(bool enable) // set_enabled shouldn't be done on the worker thread. if (mPeerConnection) { - mPeerConnection->SetAudioRecording(enable); auto senders = mPeerConnection->GetSenders(); for (auto &sender : senders) { @@ -938,7 +994,7 @@ void LLWebRTCPeerConnectionImpl::AnswerAvailable(const std::string &sdp) { RTC_LOG(LS_INFO) << __FUNCTION__ << " " << mPeerConnection->peer_connection_state(); mPeerConnection->SetRemoteDescription(webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, sdp), - rtc::scoped_refptr(this)); + webrtc::scoped_refptr(this)); } }); } @@ -951,22 +1007,22 @@ void LLWebRTCPeerConnectionImpl::AnswerAvailable(const std::string &sdp) void LLWebRTCPeerConnectionImpl::setMute(bool mute) { EMicMuteState new_state = mute ? MUTE_MUTED : MUTE_UNMUTED; - if (new_state == mMute) - { - return; // no change - } + + // even if mute hasn't changed, we still need to update the mute + // state on the connections to handle cases where the 'Default' device + // has changed in the OS (unplugged headset, etc.) which messes + // with the mute state. + bool force_reset = mMute == MUTE_INITIAL && mute; bool enable = !mute; mMute = new_state; + mWebRTCImpl->PostSignalingTask( [this, force_reset, enable]() { if (mPeerConnection) { - // SetAudioRecording must be called before enabling/disabling tracks. - mPeerConnection->SetAudioRecording(enable); - auto senders = mPeerConnection->GetSenders(); RTC_LOG(LS_INFO) << __FUNCTION__ << (mMute ? "disabling" : "enabling") << " streams count " << senders.size(); @@ -1046,14 +1102,14 @@ void LLWebRTCPeerConnectionImpl::setSendVolume(float volume) // PeerConnectionObserver implementation. // -void LLWebRTCPeerConnectionImpl::OnAddTrack(rtc::scoped_refptr receiver, - const std::vector> &streams) +void LLWebRTCPeerConnectionImpl::OnAddTrack(webrtc::scoped_refptr receiver, + const std::vector> &streams) { RTC_LOG(LS_INFO) << __FUNCTION__ << " " << receiver->id(); webrtc::RtpParameters params; webrtc::RtpCodecParameters codecparam; codecparam.name = "opus"; - codecparam.kind = cricket::MEDIA_TYPE_AUDIO; + codecparam.kind = webrtc::MediaType::AUDIO; codecparam.clock_rate = 48000; codecparam.num_channels = 2; codecparam.parameters["stereo"] = "1"; @@ -1062,12 +1118,12 @@ void LLWebRTCPeerConnectionImpl::OnAddTrack(rtc::scoped_refptrSetParameters(params); } -void LLWebRTCPeerConnectionImpl::OnRemoveTrack(rtc::scoped_refptr receiver) +void LLWebRTCPeerConnectionImpl::OnRemoveTrack(webrtc::scoped_refptr receiver) { RTC_LOG(LS_INFO) << __FUNCTION__ << " " << receiver->id(); } -void LLWebRTCPeerConnectionImpl::OnDataChannel(rtc::scoped_refptr channel) +void LLWebRTCPeerConnectionImpl::OnDataChannel(webrtc::scoped_refptr channel) { if (mDataChannel) { @@ -1154,23 +1210,23 @@ static std::string iceCandidateToTrickleString(const webrtc::IceCandidateInterfa candidate->candidate().address().ipaddr().ToString() << " " << candidate->candidate().address().PortAsString() << " typ "; - if (candidate->candidate().type() == cricket::LOCAL_PORT_TYPE) + if (candidate->candidate().type() == webrtc::IceCandidateType::kHost) { candidate_stream << "host"; } - else if (candidate->candidate().type() == cricket::STUN_PORT_TYPE) + else if (candidate->candidate().type() == webrtc::IceCandidateType::kSrflx) { candidate_stream << "srflx " << "raddr " << candidate->candidate().related_address().ipaddr().ToString() << " " << "rport " << candidate->candidate().related_address().PortAsString(); } - else if (candidate->candidate().type() == cricket::RELAY_PORT_TYPE) + else if (candidate->candidate().type() == webrtc::IceCandidateType::kRelay) { candidate_stream << "relay " << "raddr " << candidate->candidate().related_address().ipaddr().ToString() << " " << "rport " << candidate->candidate().related_address().PortAsString(); } - else if (candidate->candidate().type() == cricket::PRFLX_PORT_TYPE) + else if (candidate->candidate().type() == webrtc::IceCandidateType::kPrflx) { candidate_stream << "prflx " << "raddr " << candidate->candidate().related_address().ipaddr().ToString() << " " << @@ -1265,7 +1321,7 @@ void LLWebRTCPeerConnectionImpl::OnSuccess(webrtc::SessionDescriptionInterface * mPeerConnection->SetLocalDescription(std::unique_ptr( webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, mangled_sdp)), - rtc::scoped_refptr(this)); + webrtc::scoped_refptr(this)); } @@ -1375,7 +1431,7 @@ void LLWebRTCPeerConnectionImpl::sendData(const std::string& data, bool binary) { if (mDataChannel) { - rtc::CopyOnWriteBuffer cowBuffer(data.data(), data.length()); + webrtc::CopyOnWriteBuffer cowBuffer(data.data(), data.length()); webrtc::DataBuffer buffer(cowBuffer, binary); mWebRTCImpl->PostNetworkTask([this, buffer]() { if (mDataChannel) diff --git a/indra/llwebrtc/llwebrtc.h b/indra/llwebrtc/llwebrtc.h index c6fdb909ddc..7d06b7d2b40 100644 --- a/indra/llwebrtc/llwebrtc.h +++ b/indra/llwebrtc/llwebrtc.h @@ -159,7 +159,10 @@ class LLWebRTCDeviceInterface virtual void setTuningMode(bool enable) = 0; virtual float getTuningAudioLevel() = 0; // for use during tuning virtual float getPeerConnectionAudioLevel() = 0; // for use when not tuning - virtual void setPeerConnectionGain(float gain) = 0; + virtual void setMicGain(float gain) = 0; + virtual void setTuningMicGain(float gain) = 0; + + virtual void setMute(bool mute, int delay_ms = 0) = 0; }; // LLWebRTCAudioInterface provides the viewer with a way diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h index b6294dbd4a5..51d42c82b24 100644 --- a/indra/llwebrtc/llwebrtc_impl.h +++ b/indra/llwebrtc/llwebrtc_impl.h @@ -54,12 +54,12 @@ #include "rtc_base/ref_counted_object.h" #include "rtc_base/ssl_adapter.h" #include "rtc_base/thread.h" +#include "rtc_base/logging.h" #include "api/peer_connection_interface.h" #include "api/media_stream_interface.h" #include "api/create_peerconnection_factory.h" #include "modules/audio_device/include/audio_device.h" #include "modules/audio_device/include/audio_device_data_observer.h" -#include "rtc_base/task_queue.h" #include "api/task_queue/task_queue_factory.h" #include "api/task_queue/default_task_queue_factory.h" #include "modules/audio_device/include/audio_device_defines.h" @@ -69,35 +69,30 @@ namespace llwebrtc class LLWebRTCPeerConnectionImpl; -class LLWebRTCLogSink : public rtc::LogSink { +class LLWebRTCLogSink : public webrtc::LogSink +{ public: - LLWebRTCLogSink(LLWebRTCLogCallback* callback) : - mCallback(callback) - { - } + LLWebRTCLogSink(LLWebRTCLogCallback* callback) : mCallback(callback) {} // Destructor: close the log file - ~LLWebRTCLogSink() override - { - } + ~LLWebRTCLogSink() override {} - void OnLogMessage(const std::string& msg, - rtc::LoggingSeverity severity) override + void OnLogMessage(const std::string& msg, webrtc::LoggingSeverity severity) override { if (mCallback) { - switch(severity) + switch (severity) { - case rtc::LS_VERBOSE: + case webrtc::LS_VERBOSE: mCallback->LogMessage(LLWebRTCLogCallback::LOG_LEVEL_VERBOSE, msg); break; - case rtc::LS_INFO: + case webrtc::LS_INFO: mCallback->LogMessage(LLWebRTCLogCallback::LOG_LEVEL_VERBOSE, msg); break; - case rtc::LS_WARNING: + case webrtc::LS_WARNING: mCallback->LogMessage(LLWebRTCLogCallback::LOG_LEVEL_VERBOSE, msg); break; - case rtc::LS_ERROR: + case webrtc::LS_ERROR: mCallback->LogMessage(LLWebRTCLogCallback::LOG_LEVEL_VERBOSE, msg); break; default: @@ -118,73 +113,307 @@ class LLWebRTCLogSink : public rtc::LogSink { LLWebRTCLogCallback* mCallback; }; -// Implements a class allowing capture of audio data -// to determine audio level of the microphone. -class LLAudioDeviceObserver : public webrtc::AudioDeviceDataObserver +// ----------------------------------------------------------------------------- +// A proxy transport that forwards capture data to two AudioTransport sinks: +// - the "engine" (libwebrtc's VoiceEngine) +// - the "user" (your app's listener) +// +// Playout (NeedMorePlayData) goes only to the engine by default to avoid +// double-writing into the output buffer. See notes below if you want a tap. +// ----------------------------------------------------------------------------- +class LLWebRTCAudioTransport : public webrtc::AudioTransport { - public: - LLAudioDeviceObserver(); - - // Retrieve the RMS audio loudness - float getMicrophoneEnergy(); - - // Data retrieved from the caputure device is - // passed in here for processing. - void OnCaptureData(const void *audio_samples, - const size_t num_samples, - const size_t bytes_per_sample, - const size_t num_channels, - const uint32_t samples_per_sec) override; - - // This is for data destined for the render device. - // not currently used. - void OnRenderData(const void *audio_samples, - const size_t num_samples, - const size_t bytes_per_sample, - const size_t num_channels, - const uint32_t samples_per_sec) override; +public: + LLWebRTCAudioTransport(); + + void SetEngineTransport(webrtc::AudioTransport* t); + + // -------- Capture path: fan out to both sinks -------- + int32_t RecordedDataIsAvailable(const void* audio_data, + size_t number_of_samples, + size_t bytes_per_sample, + size_t number_of_channels, + uint32_t samples_per_sec, + uint32_t total_delay_ms, + int32_t clock_drift, + uint32_t current_mic_level, + bool key_pressed, + uint32_t& new_mic_level) override; + + // -------- Playout path: delegate to engine only -------- + int32_t NeedMorePlayData(size_t number_of_samples, + size_t bytes_per_sample, + size_t number_of_channels, + uint32_t samples_per_sec, + void* audio_data, + size_t& number_of_samples_out, + int64_t* elapsed_time_ms, + int64_t* ntp_time_ms) override; + + // Method to pull mixed render audio data from all active VoE channels. + // The data will not be passed as reference for audio processing internally. + void PullRenderData(int bits_per_sample, + int sample_rate, + size_t number_of_channels, + size_t number_of_frames, + void* audio_data, + int64_t* elapsed_time_ms, + int64_t* ntp_time_ms) override; + + float GetMicrophoneEnergy() { return mMicrophoneEnergy.load(std::memory_order_relaxed); } + void SetGain(float gain) { mGain.store(gain, std::memory_order_relaxed); } + +private: + std::atomic engine_{ nullptr }; + static const int NUM_PACKETS_TO_FILTER = 30; // 300 ms of smoothing (30 frames) + float mSumVector[NUM_PACKETS_TO_FILTER]; + std::atomic mMicrophoneEnergy; + std::atomic mGain{ 0.0f }; - protected: - static const int NUM_PACKETS_TO_FILTER = 30; // 300 ms of smoothing (30 frames) - float mSumVector[NUM_PACKETS_TO_FILTER]; - float mMicrophoneEnergy; }; + +// ----------------------------------------------------------------------------- +// LLWebRTCAudioDeviceModule +// - Wraps a real ADM to provide microphone energy for tuning +// ----------------------------------------------------------------------------- +class LLWebRTCAudioDeviceModule : public webrtc::AudioDeviceModule +{ +public: + explicit LLWebRTCAudioDeviceModule(webrtc::scoped_refptr inner) : inner_(std::move(inner)), tuning_(false) + { + RTC_CHECK(inner_); + } + + // ----- AudioDeviceModule interface: we mostly forward to |inner_| ----- + int32_t ActiveAudioLayer(AudioLayer* audioLayer) const override { return inner_->ActiveAudioLayer(audioLayer); } + + int32_t RegisterAudioCallback(webrtc::AudioTransport* engine_transport) override + { + // The engine registers its transport here. We put our audio transport between engine and ADM. + audio_transport_.SetEngineTransport(engine_transport); + // Register our proxy with the real ADM. + return inner_->RegisterAudioCallback(&audio_transport_); + } + + int32_t Init() override { return inner_->Init(); } + int32_t Terminate() override { return inner_->Terminate(); } + bool Initialized() const override { return inner_->Initialized(); } + + // --- Device enumeration/selection (forward) --- + int16_t PlayoutDevices() override { return inner_->PlayoutDevices(); } + int16_t RecordingDevices() override { return inner_->RecordingDevices(); } + int32_t PlayoutDeviceName(uint16_t index, char name[webrtc::kAdmMaxDeviceNameSize], char guid[webrtc::kAdmMaxGuidSize]) override + { + return inner_->PlayoutDeviceName(index, name, guid); + } + int32_t RecordingDeviceName(uint16_t index, char name[webrtc::kAdmMaxDeviceNameSize], char guid[webrtc::kAdmMaxGuidSize]) override + { + return inner_->RecordingDeviceName(index, name, guid); + } + int32_t SetPlayoutDevice(uint16_t index) override { return inner_->SetPlayoutDevice(index); } + int32_t SetRecordingDevice(uint16_t index) override { return inner_->SetRecordingDevice(index); } + + // Windows default/communications selectors, if your branch exposes them: + int32_t SetPlayoutDevice(WindowsDeviceType type) override { return inner_->SetPlayoutDevice(type); } + int32_t SetRecordingDevice(WindowsDeviceType type) override { return inner_->SetRecordingDevice(type); } + + // --- Init/start/stop (forward) --- + int32_t InitPlayout() override { return inner_->InitPlayout(); } + bool PlayoutIsInitialized() const override { return inner_->PlayoutIsInitialized(); } + int32_t StartPlayout() override { + if (tuning_) return 0; // For tuning, don't allow playout + return inner_->StartPlayout(); + } + int32_t StopPlayout() override { return inner_->StopPlayout(); } + bool Playing() const override { return inner_->Playing(); } + + int32_t InitRecording() override { return inner_->InitRecording(); } + bool RecordingIsInitialized() const override { return inner_->RecordingIsInitialized(); } + int32_t StartRecording() override { + // ignore start recording as webrtc.lib will + // send one when streams first connect, resulting + // in an inadvertant 'recording' when mute is on. + // We take full control of StartRecording via + // ForceStartRecording below. + return 0; + } + int32_t StopRecording() override { + if (tuning_) return 0; // if we're tuning, disregard the StopRecording we get from disabling the streams + return inner_->StopRecording(); + } + int32_t ForceStartRecording() { return inner_->StartRecording(); } + int32_t ForceStopRecording() { return inner_->StopRecording(); } + bool Recording() const override { return inner_->Recording(); } + + // --- Stereo opts (forward if available on your branch) --- + int32_t SetStereoPlayout(bool enable) override { return inner_->SetStereoPlayout(enable); } + int32_t SetStereoRecording(bool enable) override { return inner_->SetStereoRecording(enable); } + int32_t PlayoutIsAvailable(bool* available) override { return inner_->PlayoutIsAvailable(available); } + int32_t RecordingIsAvailable(bool* available) override { return inner_->RecordingIsAvailable(available); } + + // --- AGC/Volume/Mute/etc. (forward) --- + int32_t SetMicrophoneVolume(uint32_t volume) override { return inner_->SetMicrophoneVolume(volume); } + int32_t MicrophoneVolume(uint32_t* volume) const override { return inner_->MicrophoneVolume(volume); } + + // --- Speaker/Microphone init (forward) --- + int32_t InitSpeaker() override { return inner_->InitSpeaker(); } + bool SpeakerIsInitialized() const override { return inner_->SpeakerIsInitialized(); } + int32_t InitMicrophone() override { return inner_->InitMicrophone(); } + bool MicrophoneIsInitialized() const override { return inner_->MicrophoneIsInitialized(); } + + // --- Speaker Volume (forward) --- + int32_t SpeakerVolumeIsAvailable(bool* available) override { return inner_->SpeakerVolumeIsAvailable(available); } + int32_t SetSpeakerVolume(uint32_t volume) override { return inner_->SetSpeakerVolume(volume); } + int32_t SpeakerVolume(uint32_t* volume) const override { return inner_->SpeakerVolume(volume); } + int32_t MaxSpeakerVolume(uint32_t* maxVolume) const override { return inner_->MaxSpeakerVolume(maxVolume); } + int32_t MinSpeakerVolume(uint32_t* minVolume) const override { return inner_->MinSpeakerVolume(minVolume); } + + // --- Microphone Volume (forward) --- + int32_t MicrophoneVolumeIsAvailable(bool* available) override { return inner_->MicrophoneVolumeIsAvailable(available); } + int32_t MaxMicrophoneVolume(uint32_t* maxVolume) const override { return inner_->MaxMicrophoneVolume(maxVolume); } + int32_t MinMicrophoneVolume(uint32_t* minVolume) const override { return inner_->MinMicrophoneVolume(minVolume); } + + // --- Speaker Mute (forward) --- + int32_t SpeakerMuteIsAvailable(bool* available) override { return inner_->SpeakerMuteIsAvailable(available); } + int32_t SetSpeakerMute(bool enable) override { return inner_->SetSpeakerMute(enable); } + int32_t SpeakerMute(bool* enabled) const override { return inner_->SpeakerMute(enabled); } + + // --- Microphone Mute (forward) --- + int32_t MicrophoneMuteIsAvailable(bool* available) override { return inner_->MicrophoneMuteIsAvailable(available); } + int32_t SetMicrophoneMute(bool enable) override { return inner_->SetMicrophoneMute(enable); } + int32_t MicrophoneMute(bool* enabled) const override { return inner_->MicrophoneMute(enabled); } + + // --- Stereo Support (forward) --- + int32_t StereoPlayoutIsAvailable(bool* available) const override { return inner_->StereoPlayoutIsAvailable(available); } + int32_t StereoPlayout(bool* enabled) const override { return inner_->StereoPlayout(enabled); } + int32_t StereoRecordingIsAvailable(bool* available) const override { return inner_->StereoRecordingIsAvailable(available); } + int32_t StereoRecording(bool* enabled) const override { return inner_->StereoRecording(enabled); } + + // --- Delay/Timing (forward) --- + int32_t PlayoutDelay(uint16_t* delayMS) const override { return inner_->PlayoutDelay(delayMS); } + + // --- Built-in Audio Processing (forward) --- + bool BuiltInAECIsAvailable() const override { return inner_->BuiltInAECIsAvailable(); } + bool BuiltInAGCIsAvailable() const override { return inner_->BuiltInAGCIsAvailable(); } + bool BuiltInNSIsAvailable() const override { return inner_->BuiltInNSIsAvailable(); } + int32_t EnableBuiltInAEC(bool enable) override { return inner_->EnableBuiltInAEC(enable); } + int32_t EnableBuiltInAGC(bool enable) override { return inner_->EnableBuiltInAGC(enable); } + int32_t EnableBuiltInNS(bool enable) override { return inner_->EnableBuiltInNS(enable); } + + // --- Additional AudioDeviceModule methods (forward) --- + int32_t GetPlayoutUnderrunCount() const override { return inner_->GetPlayoutUnderrunCount(); } + + // Used to generate RTC stats. If not implemented, RTCAudioPlayoutStats will + // not be present in the stats. + std::optional GetStats() const override { return inner_->GetStats(); } + +// Only supported on iOS. +#if defined(WEBRTC_IOS) + virtual int GetPlayoutAudioParameters(AudioParameters* params) const override { return inner_->GetPlayoutAudioParameters(params); } + virtual int GetRecordAudioParameters(AudioParameters* params) override { return inner_->GetRecordAudioParameters(params); } +#endif // WEBRTC_IOS + + virtual int32_t GetPlayoutDevice() const override { return inner_->GetPlayoutDevice(); } + virtual int32_t GetRecordingDevice() const override { return inner_->GetRecordingDevice(); } + virtual int32_t SetObserver(webrtc::AudioDeviceObserver* observer) override { return inner_->SetObserver(observer); } + + // tuning microphone energy calculations + float GetMicrophoneEnergy() { return audio_transport_.GetMicrophoneEnergy(); } + void SetTuningMicGain(float gain) { audio_transport_.SetGain(gain); } + void SetTuning(bool tuning, bool mute) + { + tuning_ = tuning; + if (tuning) + { + inner_->InitRecording(); + inner_->StartRecording(); + inner_->StopPlayout(); + } + else + { + if (mute) + { + inner_->StopRecording(); + } + else + { + inner_->InitRecording(); + inner_->StartRecording(); + } + inner_->StartPlayout(); + } + } + +protected: + ~LLWebRTCAudioDeviceModule() override = default; + +private: + webrtc::scoped_refptr inner_; + LLWebRTCAudioTransport audio_transport_; + + bool tuning_; +}; + +class LLCustomProcessorState +{ + +public: + float getMicrophoneEnergy() { return mMicrophoneEnergy.load(std::memory_order_relaxed); } + void setMicrophoneEnergy(float energy) { mMicrophoneEnergy.store(energy, std::memory_order_relaxed); } + + void setGain(float gain) + { + mGain.store(gain, std::memory_order_relaxed); + mDirty.store(true, std::memory_order_relaxed); + } + + float getGain() { return mGain.load(std::memory_order_relaxed); } + + bool getDirty() { return mDirty.exchange(false, std::memory_order_relaxed); } + + protected: + std::atomic mDirty{ true }; + std::atomic mMicrophoneEnergy{ 0.0f }; + std::atomic mGain{ 0.0f }; +}; + +using LLCustomProcessorStatePtr = std::shared_ptr; + // Used to process/retrieve audio levels after // all of the processing (AGC, AEC, etc.) for display in-world to the user. class LLCustomProcessor : public webrtc::CustomProcessing { - public: - LLCustomProcessor(); +public: + LLCustomProcessor(LLCustomProcessorStatePtr state); ~LLCustomProcessor() override {} // (Re-) Initializes the submodule. void Initialize(int sample_rate_hz, int num_channels) override; // Analyzes the given capture or render signal. - void Process(webrtc::AudioBuffer *audio) override; + void Process(webrtc::AudioBuffer* audio) override; // Returns a string representation of the module state. std::string ToString() const override { return ""; } - float getMicrophoneEnergy() { return mMicrophoneEnergy; } - - void setGain(float gain) { mGain = gain; } - - protected: - static const int NUM_PACKETS_TO_FILTER = 30; // 300 ms of smoothing - int mSampleRateHz; - int mNumChannels; +protected: + static const int NUM_PACKETS_TO_FILTER = 30; // 300 ms of smoothing + int mSampleRateHz{ 48000 }; + int mNumChannels{ 2 }; + int mRampFrames{ 2 }; + float mCurrentGain{ 0.0f }; + float mGainStep{ 0.0f }; float mSumVector[NUM_PACKETS_TO_FILTER]; - float mMicrophoneEnergy; - float mGain; + friend LLCustomProcessorState; + LLCustomProcessorStatePtr mState; }; // Primary singleton implementation for interfacing // with the native webrtc library. -class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceSink +class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceObserver { public: LLWebRTCImpl(LLWebRTCLogCallback* logCallback); @@ -214,10 +443,15 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS float getTuningAudioLevel() override; float getPeerConnectionAudioLevel() override; - void setPeerConnectionGain(float gain) override; + void setMicGain(float gain) override; + void setTuningMicGain(float gain) override; + + void setMute(bool mute, int delay_ms = 20) override; + + void intSetMute(bool mute, int delay_ms = 20); // - // AudioDeviceSink + // AudioDeviceObserver // void OnDevicesUpdated() override; @@ -246,19 +480,19 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS mNetworkThread->PostTask(std::move(task), location); } - void WorkerBlockingCall(rtc::FunctionView functor, + void WorkerBlockingCall(webrtc::FunctionView functor, const webrtc::Location& location = webrtc::Location::Current()) { mWorkerThread->BlockingCall(std::move(functor), location); } - void SignalingBlockingCall(rtc::FunctionView functor, + void SignalingBlockingCall(webrtc::FunctionView functor, const webrtc::Location& location = webrtc::Location::Current()) { mSignalingThread->BlockingCall(std::move(functor), location); } - void NetworkBlockingCall(rtc::FunctionView functor, + void NetworkBlockingCall(webrtc::FunctionView functor, const webrtc::Location& location = webrtc::Location::Current()) { mNetworkThread->BlockingCall(std::move(functor), location); @@ -266,7 +500,7 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS // Allows the LLWebRTCPeerConnectionImpl class to retrieve the // native webrtc PeerConnectionFactory. - rtc::scoped_refptr getPeerConnectionFactory() + webrtc::scoped_refptr getPeerConnectionFactory() { return mPeerConnectionFactory; } @@ -275,49 +509,47 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS LLWebRTCPeerConnectionInterface* newPeerConnection(); void freePeerConnection(LLWebRTCPeerConnectionInterface* peer_connection); - // enables/disables capture via the capture device - void setRecording(bool recording); - - void setPlayout(bool playing); - protected: + + void workerDeployDevices(); LLWebRTCLogSink* mLogSink; // The native webrtc threads - std::unique_ptr mNetworkThread; - std::unique_ptr mWorkerThread; - std::unique_ptr mSignalingThread; + std::unique_ptr mNetworkThread; + std::unique_ptr mWorkerThread; + std::unique_ptr mSignalingThread; // The factory that allows creation of native webrtc PeerConnections. - rtc::scoped_refptr mPeerConnectionFactory; + webrtc::scoped_refptr mPeerConnectionFactory; - rtc::scoped_refptr mAudioProcessingModule; + webrtc::scoped_refptr mAudioProcessingModule; // more native webrtc stuff - std::unique_ptr mTaskQueueFactory; + std::unique_ptr mTaskQueueFactory; // Devices void updateDevices(); - rtc::scoped_refptr mTuningDeviceModule; - rtc::scoped_refptr mPeerDeviceModule; + void deployDevices(); + std::atomic mDevicesDeploying; + webrtc::scoped_refptr mDeviceModule; std::vector mVoiceDevicesObserverList; // accessors in native webrtc for devices aren't apparently implemented yet. bool mTuningMode; - int32_t mRecordingDevice; + std::string mRecordingDevice; LLWebRTCVoiceDeviceList mRecordingDeviceList; - int32_t mPlayoutDevice; + std::string mPlayoutDevice; LLWebRTCVoiceDeviceList mPlayoutDeviceList; bool mMute; + float mGain; - LLAudioDeviceObserver * mTuningAudioDeviceObserver; - LLCustomProcessor * mPeerCustomProcessor; + LLCustomProcessorStatePtr mPeerCustomProcessor; // peer connections - std::vector> mPeerConnections; + std::vector> mPeerConnections; }; @@ -342,7 +574,7 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface, void terminate(); virtual void AddRef() const override = 0; - virtual rtc::RefCountReleaseStatus Release() const override = 0; + virtual webrtc::RefCountReleaseStatus Release() const override = 0; // // LLWebRTCPeerConnection @@ -373,10 +605,10 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface, // void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override {} - void OnAddTrack(rtc::scoped_refptr receiver, - const std::vector> &streams) override; - void OnRemoveTrack(rtc::scoped_refptr receiver) override; - void OnDataChannel(rtc::scoped_refptr channel) override; + void OnAddTrack(webrtc::scoped_refptr receiver, + const std::vector> &streams) override; + void OnRemoveTrack(webrtc::scoped_refptr receiver) override; + void OnDataChannel(webrtc::scoped_refptr channel) override; void OnRenegotiationNeeded() override {} void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) override {}; void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) override; @@ -415,7 +647,7 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface, LLWebRTCImpl * mWebRTCImpl; - rtc::scoped_refptr mPeerConnectionFactory; + webrtc::scoped_refptr mPeerConnectionFactory; typedef enum { MUTE_INITIAL, @@ -429,12 +661,12 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface, std::vector> mCachedIceCandidates; bool mAnswerReceived; - rtc::scoped_refptr mPeerConnection; - rtc::scoped_refptr mLocalStream; + webrtc::scoped_refptr mPeerConnection; + webrtc::scoped_refptr mLocalStream; // data std::vector mDataObserverList; - rtc::scoped_refptr mDataChannel; + webrtc::scoped_refptr mDataChannel; }; } diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 34f3e22182f..b26a48fd5f8 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -82,9 +82,15 @@ const std::string WEBRTC_VOICE_SERVER_TYPE = "webrtc"; namespace { - const F32 MAX_AUDIO_DIST = 50.0f; - const F32 VOLUME_SCALE_WEBRTC = 0.01f; - const F32 LEVEL_SCALE_WEBRTC = 0.008f; + const F32 MAX_AUDIO_DIST = 50.0f; + const F32 VOLUME_SCALE_WEBRTC = 0.01f; + const F32 TUNING_LEVEL_SCALE = 0.01f; + const F32 TUNING_LEVEL_START_POINT = 0.8f; + const F32 LEVEL_SCALE = 0.005f; + const F32 LEVEL_START_POINT = 0.18f; + const uint32_t SET_HIDDEN_RESTORE_DELAY_MS = 200; // 200 ms to unmute again after hiding during teleport + const uint32_t MUTE_FADE_DELAY_MS = 500; // 20ms fade followed by 480ms silence gets rid of the click just after unmuting. + // This is because the buffers and processing is cleared by the silence. const F32 SPEAKING_AUDIO_LEVEL = 0.30; @@ -201,7 +207,6 @@ bool LLWebRTCVoiceClient::sShuttingDown = false; LLWebRTCVoiceClient::LLWebRTCVoiceClient() : mHidden(false), - mTuningMode(false), mTuningMicGain(0.0), mTuningSpeakerVolume(50), // Set to 50 so the user can hear themselves when he sets his mic volume mDevicesListUpdated(false), @@ -348,25 +353,45 @@ void LLWebRTCVoiceClient::updateSettings() static LLCachedControl sOutputDevice(gSavedSettings, "VoiceOutputAudioDevice"); setRenderDevice(sOutputDevice); - LL_INFOS("Voice") << "Input device: " << std::quoted(sInputDevice()) << ", output device: " << std::quoted(sOutputDevice()) << LL_ENDL; + LL_INFOS("Voice") << "Input device: " << std::quoted(sInputDevice()) << ", output device: " << std::quoted(sOutputDevice()) + << LL_ENDL; static LLCachedControl sMicLevel(gSavedSettings, "AudioLevelMic"); setMicGain(sMicLevel); llwebrtc::LLWebRTCDeviceInterface::AudioConfig config; + bool audioConfigChanged = false; + static LLCachedControl sEchoCancellation(gSavedSettings, "VoiceEchoCancellation", true); - config.mEchoCancellation = sEchoCancellation; + if (sEchoCancellation != config.mEchoCancellation) + { + config.mEchoCancellation = sEchoCancellation; + audioConfigChanged = true; + } static LLCachedControl sAGC(gSavedSettings, "VoiceAutomaticGainControl", true); - config.mAGC = sAGC; + if (sAGC != config.mAGC) + { + config.mAGC = sAGC; + audioConfigChanged = true; + } - static LLCachedControl sNoiseSuppressionLevel(gSavedSettings, + static LLCachedControl sNoiseSuppressionLevel( + gSavedSettings, "VoiceNoiseSuppressionLevel", llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel::NOISE_SUPPRESSION_LEVEL_VERY_HIGH); - config.mNoiseSuppressionLevel = (llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel)(U32)sNoiseSuppressionLevel; - - mWebRTCDeviceInterface->setAudioConfig(config); + auto noiseSuppressionLevel = + (llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel)(U32)sNoiseSuppressionLevel; + if (noiseSuppressionLevel != config.mNoiseSuppressionLevel) + { + config.mNoiseSuppressionLevel = noiseSuppressionLevel; + audioConfigChanged = true; + } + if (audioConfigChanged) + { + mWebRTCDeviceInterface->setAudioConfig(config); + } } } @@ -695,21 +720,38 @@ void LLWebRTCVoiceClient::OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDevi std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice"); LL_DEBUGS("Voice") << "Setting devices to-input: '" << inputDevice << "' output: '" << outputDevice << "'" << LL_ENDL; - clearRenderDevices(); - for (auto &device : render_devices) + + // only set the render device if the device list has changed. + if (mRenderDevices.size() != render_devices.size() || !std::equal(mRenderDevices.begin(), + mRenderDevices.end(), + render_devices.begin(), + [](const LLVoiceDevice& a, const llwebrtc::LLWebRTCVoiceDevice& b) { + return a.display_name == b.mDisplayName && a.full_name == b.mID; })) { - addRenderDevice(LLVoiceDevice(device.mDisplayName, device.mID)); + clearRenderDevices(); + for (auto& device : render_devices) + { + addRenderDevice(LLVoiceDevice(device.mDisplayName, device.mID)); + } + setRenderDevice(outputDevice); } - setRenderDevice(outputDevice); - clearCaptureDevices(); - for (auto &device : capture_devices) + // only set the capture device if the device list has changed. + if (mCaptureDevices.size() != capture_devices.size() ||!std::equal(mCaptureDevices.begin(), + mCaptureDevices.end(), + capture_devices.begin(), + [](const LLVoiceDevice& a, const llwebrtc::LLWebRTCVoiceDevice& b) + { return a.display_name == b.mDisplayName && a.full_name == b.mID; })) { - LL_DEBUGS("Voice") << "Checking capture device:'" << device.mID << "'" << LL_ENDL; + clearCaptureDevices(); + for (auto& device : capture_devices) + { + LL_DEBUGS("Voice") << "Checking capture device:'" << device.mID << "'" << LL_ENDL; - addCaptureDevice(LLVoiceDevice(device.mDisplayName, device.mID)); + addCaptureDevice(LLVoiceDevice(device.mDisplayName, device.mID)); + } + setCaptureDevice(inputDevice); } - setCaptureDevice(inputDevice); setDevicesListUpdated(true); } @@ -762,7 +804,14 @@ bool LLWebRTCVoiceClient::inTuningMode() void LLWebRTCVoiceClient::tuningSetMicVolume(float volume) { - mTuningMicGain = volume; + if (volume != mTuningMicGain) + { + mTuningMicGain = volume; + if (mWebRTCDeviceInterface) + { + mWebRTCDeviceInterface->setTuningMicGain(volume); + } + } } void LLWebRTCVoiceClient::tuningSetSpeakerVolume(float volume) @@ -774,21 +823,10 @@ void LLWebRTCVoiceClient::tuningSetSpeakerVolume(float volume) } } -float LLWebRTCVoiceClient::getAudioLevel() -{ - if (mIsInTuningMode) - { - return (1.0f - mWebRTCDeviceInterface->getTuningAudioLevel() * LEVEL_SCALE_WEBRTC) * mTuningMicGain / 2.1f; - } - else - { - return (1.0f - mWebRTCDeviceInterface->getPeerConnectionAudioLevel() * LEVEL_SCALE_WEBRTC) * mMicGain / 2.1f; - } -} - float LLWebRTCVoiceClient::tuningGetEnergy(void) { - return getAudioLevel(); + float rms = mWebRTCDeviceInterface->getTuningAudioLevel(); + return TUNING_LEVEL_START_POINT - TUNING_LEVEL_SCALE * rms; } bool LLWebRTCVoiceClient::deviceSettingsAvailable() @@ -824,6 +862,11 @@ void LLWebRTCVoiceClient::setHidden(bool hidden) if (inSpatialChannel()) { + if (mWebRTCDeviceInterface) + { + mWebRTCDeviceInterface->setMute(mHidden || mMuteMic, + mHidden ? 0 : SET_HIDDEN_RESTORE_DELAY_MS); // delay 200ms so as to not pile up mutes/unmutes. + } if (mHidden) { // get out of the channel entirely @@ -990,7 +1033,6 @@ void LLWebRTCVoiceClient::updatePosition(void) { if (participant->mRegion != region->getRegionID()) { participant->mRegion = region->getRegionID(); - setMuteMic(mMuteMic); } } } @@ -1115,13 +1157,14 @@ void LLWebRTCVoiceClient::sendPositionUpdate(bool force) // Update our own volume on our participant, so it'll show up // in the UI. This is done on all sessions, so switching // sessions retains consistent volume levels. -void LLWebRTCVoiceClient::updateOwnVolume() { - F32 audio_level = 0.0; - if (!mMuteMic && !mTuningMode) +void LLWebRTCVoiceClient::updateOwnVolume() +{ + F32 audio_level = 0.0f; + if (!mMuteMic) { - audio_level = getAudioLevel(); + float rms = mWebRTCDeviceInterface->getPeerConnectionAudioLevel(); + audio_level = LEVEL_START_POINT - LEVEL_SCALE * rms; } - sessionState::for_each(boost::bind(predUpdateOwnVolume, _1, audio_level)); } @@ -1518,6 +1561,17 @@ void LLWebRTCVoiceClient::setMuteMic(bool muted) } mMuteMic = muted; + + if (mIsInTuningMode) + { + return; + } + + if (mWebRTCDeviceInterface) + { + mWebRTCDeviceInterface->setMute(muted, muted ? MUTE_FADE_DELAY_MS : 0); // delay for 40ms on mute to allow buffers to empty + } + // when you're hidden, your mic is always muted. if (!mHidden) { @@ -1556,7 +1610,10 @@ void LLWebRTCVoiceClient::setMicGain(F32 gain) if (gain != mMicGain) { mMicGain = gain; - mWebRTCDeviceInterface->setPeerConnectionGain(gain); + if (mWebRTCDeviceInterface) + { + mWebRTCDeviceInterface->setMicGain(gain); + } } } diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h index 71347f206a5..722d81fdc2b 100644 --- a/indra/newview/llvoicewebrtc.h +++ b/indra/newview/llvoicewebrtc.h @@ -444,10 +444,6 @@ class LLWebRTCVoiceClient : public LLSingleton, private: - // helper function to retrieve the audio level - // Used in multiple places. - float getAudioLevel(); - // Coroutine support methods //--- void voiceConnectionCoro(); @@ -458,7 +454,6 @@ class LLWebRTCVoiceClient : public LLSingleton, LL::WorkQueue::weak_t mMainQueue; - bool mTuningMode; F32 mTuningMicGain; int mTuningSpeakerVolume; bool mDevicesListUpdated; // set to true when the device list has been updated From 5c69ae1d66063ee683c5fda4da979f84bc0ce971 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 12 Sep 2025 23:07:47 +0300 Subject: [PATCH 137/145] #4604 Tweak range decrease isSystemMemoryLow() and factor check were too agressive for draw range. --- indra/newview/llviewermessage.cpp | 7 ++----- indra/newview/llviewertexture.cpp | 26 +++++++++++++++++++------- indra/newview/llviewertexture.h | 1 + indra/newview/llvocache.cpp | 6 ++---- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index d0e6af799c4..16b7ac33b8f 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3366,13 +3366,10 @@ void send_agent_update(bool force_send, bool send_reliable) static F32 last_draw_disatance_step = 1024; F32 memory_limited_draw_distance = gAgentCamera.mDrawDistance; - if (LLViewerTexture::sDesiredDiscardBias > 2.f && LLViewerTexture::isSystemMemoryLow()) + if (LLViewerTexture::isSystemMemoryCritical()) { // If we are low on memory, reduce requested draw distance - // Discard's bias is clamped to 4 so we need to check 2 to 4 range - // Factor is intended to go from 1.0 to 2.0 - F32 factor = 1.f + (LLViewerTexture::sDesiredDiscardBias - 2.f) / 2.f; - memory_limited_draw_distance = llmax(gAgentCamera.mDrawDistance / factor, gAgentCamera.mDrawDistance / 2.f); + memory_limited_draw_distance = llmax(gAgentCamera.mDrawDistance / LLViewerTexture::getSystemMemoryBudgetFactor(), gAgentCamera.mDrawDistance / 2.f); } if (tp_state == LLAgent::TELEPORT_ARRIVING || LLStartUp::getStartupState() < STATE_MISC) diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 7a25fb03a57..3142c9950ba 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -657,23 +657,35 @@ U32Megabytes LLViewerTexture::getFreeSystemMemory() return physical_res; } -//static -bool LLViewerTexture::isSystemMemoryLow() +S32Megabytes get_render_free_main_memory_treshold() { static LLCachedControl min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512); const U32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory); - return getFreeSystemMemory() < MIN_FREE_MAIN_MEMORY; + return MIN_FREE_MAIN_MEMORY; +} + +//static +bool LLViewerTexture::isSystemMemoryLow() +{ + return getFreeSystemMemory() < get_render_free_main_memory_treshold(); +} + +//static +bool LLViewerTexture::isSystemMemoryCritical() +{ + return getFreeSystemMemory() < get_render_free_main_memory_treshold() / 2; } F32 LLViewerTexture::getSystemMemoryBudgetFactor() { - static LLCachedControl min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512); - const S32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory); + const S32Megabytes MIN_FREE_MAIN_MEMORY(get_render_free_main_memory_treshold() / 2); S32 free_budget = (S32Megabytes)getFreeSystemMemory() - MIN_FREE_MAIN_MEMORY; if (free_budget < 0) { - // Result should range from 1 (0 free budget) to 2 (-512 free budget) - return 1.f - free_budget / MIN_FREE_MAIN_MEMORY; + // Leave some padding, otherwise we will crash out of memory before hitting factor 2. + const S32Megabytes PAD_BUFFER(32); + // Result should range from 1 at 0 free budget to 2 at -224 free budget, 2.14 at -256MB + return 1.f - free_budget / (MIN_FREE_MAIN_MEMORY - PAD_BUFFER); } return 1.f; } diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index d32c302d8e1..29376519953 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -115,6 +115,7 @@ class LLViewerTexture : public LLGLTexture static void initClass(); static void updateClass(); static bool isSystemMemoryLow(); + static bool isSystemMemoryCritical(); static F32 getSystemMemoryBudgetFactor(); LLViewerTexture(bool usemipmaps = true); diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index ac73c2def65..52a6afc2d03 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -488,13 +488,11 @@ void LLVOCacheEntry::updateDebugSettings() static const F32 MIN_RADIUS = 1.0f; F32 draw_radius = gAgentCamera.mDrawDistance; - if (LLViewerTexture::sDesiredDiscardBias > 2.f && LLViewerTexture::isSystemMemoryLow()) + if (LLViewerTexture::isSystemMemoryCritical()) { - // Discard's bias maximum is 4 so we need to check 2 to 4 range // Factor is intended to go from 1.0 to 2.0 - F32 factor = 1.f + (LLViewerTexture::sDesiredDiscardBias - 2.f) / 2.f; // For safety cap reduction at 50%, we don't want to go below half of draw distance - draw_radius = llmax(draw_radius / factor, draw_radius / 2.f); + draw_radius = llmax(draw_radius / LLViewerTexture::getSystemMemoryBudgetFactor(), draw_radius / 2.f); } const F32 clamped_min_radius = llclamp((F32) min_radius, MIN_RADIUS, draw_radius); // [1, mDrawDistance] sNearRadius = MIN_RADIUS + ((clamped_min_radius - MIN_RADIUS) * adjust_factor); From 7ec9736200d9f1a719e15462fac0a0f94cdd83af Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Mon, 15 Sep 2025 23:47:11 +0300 Subject: [PATCH 138/145] #4675 Voice indicator did not reappear after tuning resume() was trigggering sOnCurrentChannelChanged which was wiping participant list with no follow up updates. --- indra/newview/llconversationview.cpp | 2 +- indra/newview/llspeakingindicatormanager.cpp | 13 +++++++++++-- indra/newview/llvoicechannel.cpp | 4 +++- indra/newview/llvoicechannel.h | 1 + 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 0e0ab236d65..99d770b6e27 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -543,7 +543,7 @@ void LLConversationViewSession::onCurrentVoiceSessionChanged(const LLUUID& sessi { bool old_value = mIsInActiveVoiceChannel; mIsInActiveVoiceChannel = vmi->getUUID() == session_id; - mCallIconLayoutPanel->setVisible(mIsInActiveVoiceChannel); + mCallIconLayoutPanel->setVisible(mIsInActiveVoiceChannel && !LLVoiceChannel::isSuspended()); if (old_value != mIsInActiveVoiceChannel) { refresh(); diff --git a/indra/newview/llspeakingindicatormanager.cpp b/indra/newview/llspeakingindicatormanager.cpp index 532b245cedc..06458a9f3ce 100644 --- a/indra/newview/llspeakingindicatormanager.cpp +++ b/indra/newview/llspeakingindicatormanager.cpp @@ -200,8 +200,17 @@ void SpeakingIndicatorManager::cleanupSingleton() void SpeakingIndicatorManager::sOnCurrentChannelChanged(const LLUUID& /*session_id*/) { - switchSpeakerIndicators(mSwitchedIndicatorsOn, false); - mSwitchedIndicatorsOn.clear(); + if (LLVoiceChannel::isSuspended()) + { + switchSpeakerIndicators(mSwitchedIndicatorsOn, false); + mSwitchedIndicatorsOn.clear(); + } + else + { + // Multiple onParticipantsChanged can arrive at the same time + // from different sources, might want to filter by some factor. + onParticipantsChanged(); + } } void SpeakingIndicatorManager::onParticipantsChanged() diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index b3ac28eb7a6..fbe896ac27d 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -357,6 +357,8 @@ void LLVoiceChannel::suspend() { sSuspendedVoiceChannel = sCurrentVoiceChannel; sSuspended = true; + + sCurrentVoiceChannelChangedSignal(sSuspendedVoiceChannel->mSessionID); } } @@ -365,6 +367,7 @@ void LLVoiceChannel::resume() { if (sSuspended) { + sSuspended = false; // needs to be before activate() so that observers will be able to read state if (LLVoiceClient::getInstance()->voiceEnabled()) { if (sSuspendedVoiceChannel) @@ -382,7 +385,6 @@ void LLVoiceChannel::resume() LLVoiceChannelProximal::getInstance()->activate(); } } - sSuspended = false; } } diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h index 4d7bf551e12..bf119638d38 100644 --- a/indra/newview/llvoicechannel.h +++ b/indra/newview/llvoicechannel.h @@ -103,6 +103,7 @@ class LLVoiceChannel : public LLVoiceClientStatusObserver static void suspend(); static void resume(); + static bool isSuspended() { return sSuspended; } protected: virtual void setState(EState state); From c743ea2b6dc60312b29f2fb5972171ead26ee448 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Tue, 16 Sep 2025 10:36:26 -0700 Subject: [PATCH 139/145] Fix indexing problem with mac devices (#4676) * Fix indexing problem with mac devices This resulted in the wrong device being selected. Also, fix a shutdown crash where recording was not being stopped, hence the recording thread was still running on shutdown and crashed because it lost access to resources. Fix an issue with p2p calls where they're coming up muted even though the button indicates they are unmuted. * Always refresh device list on notification of device changes Even when the selected device doesn't change, we need to re-deploy it as it might have had characteristics (sampling rate, etc.) changed. Also, we need to redeploy when the Default device has changed --- indra/llwebrtc/llwebrtc.cpp | 48 +++++++++++++++++++--------------- indra/llwebrtc/llwebrtc_impl.h | 6 +++-- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp index edba2bee9ad..23e10767653 100644 --- a/indra/llwebrtc/llwebrtc.cpp +++ b/indra/llwebrtc/llwebrtc.cpp @@ -350,6 +350,16 @@ void LLWebRTCImpl::init() void LLWebRTCImpl::terminate() { + mWorkerThread->BlockingCall( + [this]() + { + if (mDeviceModule) + { + mDeviceModule->ForceStopRecording(); + mDeviceModule->StopPlayout(); + } + }); + for (auto &connection : mPeerConnections) { connection->terminate(); @@ -368,8 +378,6 @@ void LLWebRTCImpl::terminate() { if (mDeviceModule) { - mDeviceModule->StopRecording(); - mDeviceModule->StopPlayout(); mDeviceModule->Terminate(); } mDeviceModule = nullptr; @@ -442,11 +450,7 @@ void LLWebRTCImpl::unsetDevicesObserver(LLWebRTCDevicesObserver *observer) void LLWebRTCImpl::workerDeployDevices() { int16_t recordingDevice = RECORD_DEVICE_DEFAULT; -#if WEBRTC_WIN int16_t recording_device_start = 0; -#else - int16_t recording_device_start = 1; -#endif if (mRecordingDevice != "Default") { @@ -455,6 +459,12 @@ void LLWebRTCImpl::workerDeployDevices() if (mRecordingDeviceList[i].mID == mRecordingDevice) { recordingDevice = i; +#if !WEBRTC_WIN + // linux and mac devices range from 1 to the end of the list, with the index 0 being the + // 'default' device. Windows has a special 'default' device and other devices are indexed + // from 0 + recordingDevice++; +#endif break; } } @@ -479,11 +489,7 @@ void LLWebRTCImpl::workerDeployDevices() mDeviceModule->InitRecording(); int16_t playoutDevice = PLAYOUT_DEVICE_DEFAULT; -#if WEBRTC_WIN int16_t playout_device_start = 0; -#else - int16_t playout_device_start = 1; -#endif if (mPlayoutDevice != "Default") { for (int16_t i = playout_device_start; i < mPlayoutDeviceList.size(); i++) @@ -491,6 +497,12 @@ void LLWebRTCImpl::workerDeployDevices() if (mPlayoutDeviceList[i].mID == mPlayoutDevice) { playoutDevice = i; +#if !WEBRTC_WIN + // linux and mac devices range from 1 to the end of the list, with the index 0 being the + // 'default' device. Windows has a special 'default' device and other devices are indexed + // from 0 + playoutDevice++; +#endif break; } } @@ -546,20 +558,14 @@ void LLWebRTCImpl::workerDeployDevices() void LLWebRTCImpl::setCaptureDevice(const std::string &id) { - if (mRecordingDevice != id) - { - mRecordingDevice = id; - deployDevices(); - } + mRecordingDevice = id; + deployDevices(); } void LLWebRTCImpl::setRenderDevice(const std::string &id) { - if (mPlayoutDevice != id) - { - mPlayoutDevice = id; - deployDevices(); - } + mPlayoutDevice = id; + deployDevices(); } // updateDevices needs to happen on the worker thread. @@ -609,7 +615,7 @@ void LLWebRTCImpl::updateDevices() void LLWebRTCImpl::OnDevicesUpdated() { - deployDevices(); + updateDevices(); } diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h index 51d42c82b24..dee081119b6 100644 --- a/indra/llwebrtc/llwebrtc_impl.h +++ b/indra/llwebrtc/llwebrtc_impl.h @@ -239,8 +239,10 @@ class LLWebRTCAudioDeviceModule : public webrtc::AudioDeviceModule return 0; } int32_t StopRecording() override { - if (tuning_) return 0; // if we're tuning, disregard the StopRecording we get from disabling the streams - return inner_->StopRecording(); + // ignore stop recording as webrtc.lib will send one when streams shut down, + // even if there are other streams in place. Start/Stop recording are entirely + // controlled by the app + return 0; } int32_t ForceStartRecording() { return inner_->StartRecording(); } int32_t ForceStopRecording() { return inner_->StopRecording(); } From bf0f60039b33bb0b1f93431864fd6b51c2a20b5b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Wed, 17 Sep 2025 17:19:45 +0300 Subject: [PATCH 140/145] #4691 Log WebRTC termination for diagnostic purposes --- indra/newview/llvoicewebrtc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index b26a48fd5f8..b04f9837ecc 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -288,6 +288,8 @@ void LLWebRTCVoiceClient::terminate() return; } + LL_INFOS("Voice") << "Terminating WebRTC" << LL_ENDL; + mVoiceEnabled = false; llwebrtc::terminate(); From edbb7635457f01557f1831d382bddee5c578072a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 19 Sep 2025 14:10:38 +0300 Subject: [PATCH 141/145] Fix builds after update of build-variables branch --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 42fd44cf9ca..8f89db0923d 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -97,7 +97,7 @@ jobs: uses: actions/checkout@v4 with: repository: secondlife/build-variables - ref: universal + ref: master path: .build-variables - name: Checkout master-message-template From 5a0ada943de577091a9518dff651214616c3fc6a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 19 Sep 2025 18:19:00 +0300 Subject: [PATCH 142/145] #4570 Make 'About' floater use real bandwidth --- indra/newview/llappviewer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 2dabf3355a5..63d364eaa86 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3382,7 +3382,7 @@ LLSD LLAppViewer::getViewerInfo() const info["FONT_SIZE_ADJUSTMENT"] = gSavedSettings.getF32("FontScreenDPI"); info["UI_SCALE"] = gSavedSettings.getF32("UIScaleFactor"); info["DRAW_DISTANCE"] = gSavedSettings.getF32("RenderFarClip"); - info["NET_BANDWITH"] = gSavedSettings.getF32("ThrottleBandwidthKBPS"); + info["NET_BANDWITH"] = LLViewerThrottle::getMaxBandwidthKbps(); info["LOD_FACTOR"] = gSavedSettings.getF32("RenderVolumeLODFactor"); info["RENDER_QUALITY"] = (F32)gSavedSettings.getU32("RenderQualityPerformance"); info["TEXTURE_MEMORY"] = LLSD::Integer(gGLManager.mVRAM); From 3ff163887d49363e9d2d48ea343fa1c8da19c061 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 19 Sep 2025 21:27:01 +0300 Subject: [PATCH 143/145] #4695 Fix missing voice cleanup Cleanup is in LLVoiceClient::terminate() gWebRTCImpl was never deleted Added mDeviceModule security --- indra/llwebrtc/llwebrtc.cpp | 18 ++++++++++++++++-- indra/llwebrtc/llwebrtc_impl.h | 2 +- indra/newview/llvoiceclient.cpp | 9 ++++++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp index 23e10767653..828896f6202 100644 --- a/indra/llwebrtc/llwebrtc.cpp +++ b/indra/llwebrtc/llwebrtc.cpp @@ -342,8 +342,11 @@ void LLWebRTCImpl::init() mWorkerThread->PostTask( [this]() { - mDeviceModule->EnableBuiltInAEC(false); - updateDevices(); + if (mDeviceModule) + { + mDeviceModule->EnableBuiltInAEC(false); + updateDevices(); + } }); } @@ -449,6 +452,11 @@ void LLWebRTCImpl::unsetDevicesObserver(LLWebRTCDevicesObserver *observer) // must be run in the worker thread. void LLWebRTCImpl::workerDeployDevices() { + if (!mDeviceModule) + { + return; + } + int16_t recordingDevice = RECORD_DEVICE_DEFAULT; int16_t recording_device_start = 0; @@ -571,6 +579,11 @@ void LLWebRTCImpl::setRenderDevice(const std::string &id) // updateDevices needs to happen on the worker thread. void LLWebRTCImpl::updateDevices() { + if (!mDeviceModule) + { + return; + } + int16_t renderDeviceCount = mDeviceModule->PlayoutDevices(); mPlayoutDeviceList.clear(); @@ -1491,6 +1504,7 @@ void terminate() if (gWebRTCImpl) { gWebRTCImpl->terminate(); + delete gWebRTCImpl; gWebRTCImpl = nullptr; } } diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h index dee081119b6..df06cb88fa9 100644 --- a/indra/llwebrtc/llwebrtc_impl.h +++ b/indra/llwebrtc/llwebrtc_impl.h @@ -75,7 +75,7 @@ class LLWebRTCLogSink : public webrtc::LogSink LLWebRTCLogSink(LLWebRTCLogCallback* callback) : mCallback(callback) {} // Destructor: close the log file - ~LLWebRTCLogSink() override {} + ~LLWebRTCLogSink() override { mCallback = nullptr; } void OnLogMessage(const std::string& msg, webrtc::LoggingSeverity severity) override { diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 3edd2b473c3..71a9e71a9fd 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -292,7 +292,14 @@ void LLVoiceClient::setHidden(bool hidden) void LLVoiceClient::terminate() { - if (mSpatialVoiceModule) mSpatialVoiceModule->terminate(); + if (LLVivoxVoiceClient::instanceExists()) + { + LLWebRTCVoiceClient::getInstance()->terminate(); + } + if (LLVivoxVoiceClient::instanceExists()) + { + LLVivoxVoiceClient::getInstance()->terminate(); + } mSpatialVoiceModule = NULL; m_servicePump = NULL; From 1d9f87df4f1d7483c8dd68640c4138d794f71fc5 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Mon, 22 Sep 2025 19:39:19 +0300 Subject: [PATCH 144/145] #4695 Fix device update causing a crash --- indra/newview/llvoicewebrtc.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index b04f9837ecc..62bab7d24a6 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -691,7 +691,10 @@ LLVoiceDeviceList& LLWebRTCVoiceClient::getCaptureDevices() void LLWebRTCVoiceClient::setCaptureDevice(const std::string& name) { - mWebRTCDeviceInterface->setCaptureDevice(name); + if (mWebRTCDeviceInterface) + { + mWebRTCDeviceInterface->setCaptureDevice(name); + } } void LLWebRTCVoiceClient::setDevicesListUpdated(bool state) { @@ -778,7 +781,10 @@ LLVoiceDeviceList& LLWebRTCVoiceClient::getRenderDevices() void LLWebRTCVoiceClient::setRenderDevice(const std::string& name) { - mWebRTCDeviceInterface->setRenderDevice(name); + if (mWebRTCDeviceInterface) + { + mWebRTCDeviceInterface->setRenderDevice(name); + } } void LLWebRTCVoiceClient::tuningStart() From 6dba35d74e27125b39860f9a3df176d7f3a087b5 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Tue, 23 Sep 2025 20:20:05 +0300 Subject: [PATCH 145/145] #4719 use correct search query when navigating to the page --- indra/newview/llfloatersearch.cpp | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index 9762154a269..8e6a47dce5d 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -44,8 +44,22 @@ class LLSearchHandler : public LLCommandHandler { bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) { const size_t parts = tokens.size(); + // get the (optional) category for the search + std::string collection; + if (parts > 0) + { + collection = tokens[0].asString(); + } + + // get the (optional) search string + std::string search_text; + if (parts > 1) + { + search_text = tokens[1].asString(); + } + // open the search floater and perform the requested search - LLFloaterReg::showInstance("search", tokens); + LLFloaterReg::showInstance("search", llsd::map("collection", collection,"query", search_text)); return true; } }; @@ -84,25 +98,11 @@ void LLFloaterSearch::initiateSearch(const LLSD& tokens) // substituted into the final URL using the logic from the original search. subs["TYPE"] = "standard"; - const size_t parts = tokens.size(); + std::string collection = tokens.has("collection") ? tokens["collection"].asString() : ""; - // get the (optional) category for the search - std::string collection; - if (parts > 0) - { - collection = tokens[0].asString(); - } - - // get the (optional) search string - std::string search_text; - if (parts > 1) - { - search_text = tokens[1].asString(); - } + std::string search_text = tokens.has("query") ? tokens["query"].asString() : ""; - // TODO: where does category get set? I cannot find a reference to - // it in internal docs - might be conflated with values in mSearchType - std::string category; + std::string category = tokens.has("category") ? tokens["category"].asString() : ""; if (mSearchType.find(category) != mSearchType.end()) { subs["TYPE"] = category;