From 8eb2d17c7715dbe72d4719d7ed3dd05f8cb4b65e Mon Sep 17 00:00:00 2001 From: Henri Beauchamp Date: Thu, 30 Nov 2023 13:23:57 +0100 Subject: [PATCH 01/29] Fix LLGLTFMaterial hashing This PR fixes the non-working material hashing for LLGLTFMaterial instances. There are several issues in the current code, stemming to the fact that the hashing is performed on the block of the member variables: 1.- There are padding bytes between member variables, even after rearranging them to avoid most of the padding; in particular, the std::array's size is not a multiple of 4 bytes (64 bits), and most compilers will pad them to the next 4-byte aligment as a result. Note that C++ standards do not impose the zeroing of padding bytes on construction of a class instance, with only a couple exceptions (such as explicit zero-initialization). Those bytes MUST therefore be zeroed by us on construction. 2.- The TextureTransform strutcure getPacked() method did not touch some of the packed bytes, and as a result could *potentially* cause an issue for hashing when applied to a transform of another material instance. 3.- With the recent addition of the local textures tracking map, the said map cannot be hashed as a block of memory (map pairs will typically be allocated on the heap or on the stack, not in the memory block used by member variables). This PR solves all these issues and offers proper hashing of LLGLTFMaterial instances. --- indra/llprimitive/llgltfmaterial.cpp | 109 ++++++++++++++++++++++----- indra/llprimitive/llgltfmaterial.h | 62 +++++++++------ 2 files changed, 128 insertions(+), 43 deletions(-) diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp index ae165f7fa4..e9d3350ee9 100644 --- a/indra/llprimitive/llgltfmaterial.cpp +++ b/indra/llprimitive/llgltfmaterial.cpp @@ -47,16 +47,49 @@ const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM_ROTATION = "rota // special UUID that indicates a null UUID in override data const LLUUID LLGLTFMaterial::GLTF_OVERRIDE_NULL_UUID = LLUUID("ffffffff-ffff-ffff-ffff-ffffffffffff"); +LLGLTFMaterial::LLGLTFMaterial() +{ + // IMPORTANT: since we use the hash of the member variables memory block of + // this class to detect changes, we must ensure that all its padding bytes + // have been zeroed out. But of course, we must leave the LLRefCount member + // variable untouched (and skip it when hashing), and we cannot either + // touch the local texture overrides map (else we destroy pointers, and + // sundry private data, which would lead to a crash when using that map). + // The variable members have therefore been arranged so that anything, + // starting at mLocalTexDataDigest and up to the end of the members, can be + // safely zeroed. HB + const size_t offset = intptr_t(&mLocalTexDataDigest) - intptr_t(this); + memset((void*)((const char*)this + offset), 0, sizeof(*this) - offset); + + // Now that we zeroed out our member variables, we can set the ones that + // should not be zero to their default value. HB + mBaseColor.set(1.f, 1.f, 1.f, 1.f); + mMetallicFactor = mRoughnessFactor = 1.f; + mAlphaCutoff = 0.5f; + for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) + { + mTextureTransform[i].mScale.set(1.f, 1.f); +#if 0 + mTextureTransform[i].mOffset.clear(); + mTextureTransform[i].mRotation = 0.f; +#endif + } +#if 0 + mLocalTexDataDigest = 0; + mAlphaMode = ALPHA_MODE_OPAQUE; // This is 0 + mOverrideDoubleSided = mOverrideAlphaMode = false; +#endif +} + void LLGLTFMaterial::TextureTransform::getPacked(F32 (&packed)[8]) const { packed[0] = mScale.mV[VX]; packed[1] = mScale.mV[VY]; packed[2] = mRotation; - // packed[3] = unused packed[4] = mOffset.mV[VX]; packed[5] = mOffset.mV[VY]; - // packed[6] = unused - // packed[7] = unused + // Not used but nonetheless zeroed for proper hashing. HB + packed[3] = packed[6] = packed[7] = 0.f; } bool LLGLTFMaterial::TextureTransform::operator==(const TextureTransform& other) const @@ -89,13 +122,37 @@ LLGLTFMaterial& LLGLTFMaterial::operator=(const LLGLTFMaterial& rhs) mOverrideDoubleSided = rhs.mOverrideDoubleSided; mOverrideAlphaMode = rhs.mOverrideAlphaMode; - mTrackingIdToLocalTexture = rhs.mTrackingIdToLocalTexture; - - updateTextureTracking(); + if (rhs.mTrackingIdToLocalTexture.empty()) + { + mTrackingIdToLocalTexture.clear(); + mLocalTexDataDigest = 0; + } + else + { + mTrackingIdToLocalTexture = rhs.mTrackingIdToLocalTexture; + updateLocalTexDataDigest(); + updateTextureTracking(); + } return *this; } +void LLGLTFMaterial::updateLocalTexDataDigest() +{ + mLocalTexDataDigest = 0; + if (!mTrackingIdToLocalTexture.empty()) + { + for (local_tex_map_t::const_iterator + it = mTrackingIdToLocalTexture.begin(), + end = mTrackingIdToLocalTexture.end(); + it != end; ++it) + { + mLocalTexDataDigest ^= it->first.getDigest64() ^ + it->second.getDigest64(); + } + } +} + bool LLGLTFMaterial::operator==(const LLGLTFMaterial& rhs) const { return mTextureId == rhs.mTextureId && @@ -547,7 +604,7 @@ void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat) { LL_PROFILE_ZONE_SCOPED; - for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) + for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) { LLUUID& texture_id = mTextureId[i]; const LLUUID& override_texture_id = override_mat.mTextureId[i]; @@ -588,7 +645,7 @@ void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat) mDoubleSided = override_mat.mDoubleSided; } - for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) + for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) { if (override_mat.mTextureTransform[i].mOffset != getDefaultTextureOffset()) { @@ -606,9 +663,13 @@ void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat) } } - mTrackingIdToLocalTexture.insert(override_mat.mTrackingIdToLocalTexture.begin(), override_mat.mTrackingIdToLocalTexture.begin()); - - updateTextureTracking(); + if (!override_mat.mTrackingIdToLocalTexture.empty()) + { + auto it = override_mat.mTrackingIdToLocalTexture.begin(); + mTrackingIdToLocalTexture.insert(it, it); + updateLocalTexDataDigest(); + updateTextureTracking(); + } } void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data) @@ -618,7 +679,7 @@ void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& d // make every effort to shave bytes here - for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) + for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) { LLUUID& texture_id = mTextureId[i]; const LLUUID& override_texture_id = override_mat.mTextureId[i]; @@ -663,7 +724,7 @@ void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& d data["ds"] = override_mat.mDoubleSided; } - for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) + for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) { if (override_mat.mTextureTransform[i].mOffset != getDefaultTextureOffset()) { @@ -742,7 +803,7 @@ void LLGLTFMaterial::applyOverrideLLSD(const LLSD& data) const LLSD& ti = data["ti"]; if (ti.isArray()) { - for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) + for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) { const LLSD& o = ti[i]["o"]; if (o.isDefined()) @@ -768,27 +829,36 @@ void LLGLTFMaterial::applyOverrideLLSD(const LLSD& data) LLUUID LLGLTFMaterial::getHash() const { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - // HACK - hash the bytes of this object but don't include the ref count - LLUUID hash; - HBXXH128::digest(hash, (unsigned char*)this + sizeof(LLRefCount), sizeof(*this) - sizeof(LLRefCount)); - return hash; + // *HACK: hash the bytes of this object but do not include the ref count + // neither the local texture overrides (which is a map, with pointers to + // key/value pairs that would change from one LLGLTFMaterial instance to + // the other, even though the key/value pairs could be the same, and stored + // elsewhere in the memory heap or on the stack). + // Note: this does work properly to compare two LLGLTFMaterial instances + // only because the padding bytes between their member variables have been + // dutifully zeroed in the constructor. HB + const size_t offset = intptr_t(&mLocalTexDataDigest) - intptr_t(this); + return HBXXH128::digest((const void*)((const char*)this + offset), + sizeof(*this) - offset); } void LLGLTFMaterial::addLocalTextureTracking(const LLUUID& tracking_id, const LLUUID& tex_id) { mTrackingIdToLocalTexture[tracking_id] = tex_id; + updateLocalTexDataDigest(); } void LLGLTFMaterial::removeLocalTextureTracking(const LLUUID& tracking_id) { mTrackingIdToLocalTexture.erase(tracking_id); + updateLocalTexDataDigest(); } bool LLGLTFMaterial::replaceLocalTexture(const LLUUID& tracking_id, const LLUUID& old_id, const LLUUID& new_id) { bool res = false; - for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) + for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) { if (mTextureId[i] == old_id) { @@ -809,6 +879,7 @@ bool LLGLTFMaterial::replaceLocalTexture(const LLUUID& tracking_id, const LLUUID { mTrackingIdToLocalTexture.erase(tracking_id); } + updateLocalTexDataDigest(); return res; } diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h index 02f62fb08c..9f817d6a19 100644 --- a/indra/llprimitive/llgltfmaterial.h +++ b/indra/llprimitive/llgltfmaterial.h @@ -81,7 +81,7 @@ public: ALPHA_MODE_MASK }; - LLGLTFMaterial() {} + LLGLTFMaterial(); LLGLTFMaterial(const LLGLTFMaterial& rhs); LLGLTFMaterial& operator=(const LLGLTFMaterial& rhs); @@ -110,25 +110,6 @@ public: static const char* const GLTF_FILE_EXTENSION_TRANSFORM_ROTATION; static const LLUUID GLTF_OVERRIDE_NULL_UUID; - std::array mTextureId; - std::array mTextureTransform; - - // NOTE: initialize values to defaults according to the GLTF spec - // NOTE: these values should be in linear color space - LLColor4 mBaseColor = LLColor4(1, 1, 1, 1); - LLColor3 mEmissiveColor = LLColor3(0, 0, 0); - - F32 mMetallicFactor = 1.f; - F32 mRoughnessFactor = 1.f; - F32 mAlphaCutoff = 0.5f; - - bool mDoubleSided = false; - AlphaMode mAlphaMode = ALPHA_MODE_OPAQUE; - - // override specific flags for state that can't use off-by-epsilon or UUID hack - bool mOverrideDoubleSided = false; - bool mOverrideAlphaMode = false; - // get a UUID based on a hash of this LLGLTFMaterial LLUUID getHash() const; @@ -229,10 +210,6 @@ public: virtual bool replaceLocalTexture(const LLUUID& tracking_id, const LLUUID &old_id, const LLUUID& new_id); virtual void updateTextureTracking(); - // These fields are local to viewer and are a part of local bitmap support - typedef std::map local_tex_map_t; - local_tex_map_t mTrackingIdToLocalTexture; - protected: static LLVector2 vec2FromJson(const std::map& object, const char* key, const LLVector2& default_value); static F32 floatFromJson(const std::map& object, const char* key, const F32 default_value); @@ -249,4 +226,41 @@ protected: void writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, bool force_write = false) const; template static void writeToTexture(tinygltf::Model& model, T& texture_info, const LLUUID& texture_id, const TextureTransform& transform, bool force_write = false); + + // Used to update the digest of the mTrackingIdToLocalTexture map each time + // it is changed; this way, that digest can be used by the fast getHash() + // method intsead of having to hash all individual keys and values. HB + void updateLocalTexDataDigest(); + +public: + // These fields are local to viewer and are a part of local bitmap support + // IMPORTANT: do not move this member down (and do not move + // mLocalTexDataDigest either): the getHash() method does rely on the + // current ordering. HB + typedef std::map local_tex_map_t; + local_tex_map_t mTrackingIdToLocalTexture; + + // Used to store a digest of mTrackingIdToLocalTexture when the latter is + // not empty, or zero otherwise. HB + U64 mLocalTexDataDigest; + + std::array mTextureId; + std::array mTextureTransform; + + // NOTE: initialize values to defaults according to the GLTF spec + // NOTE: these values should be in linear color space + LLColor4 mBaseColor; + LLColor3 mEmissiveColor; + + F32 mMetallicFactor; + F32 mRoughnessFactor; + F32 mAlphaCutoff; + + AlphaMode mAlphaMode; + bool mDoubleSided; + + // Override specific flags for state that can't use off-by-epsilon or UUID + // hack + bool mOverrideDoubleSided; + bool mOverrideAlphaMode; }; From 4ca8d3417ca0d98f723cbf708cb37ca4f0eeec93 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 6 Dec 2023 01:01:06 +0200 Subject: [PATCH 02/29] SL-18107 Allow dropping inventory onto a profile for sharing --- indra/newview/llpanelavatar.cpp | 5 --- indra/newview/llpanelavatar.h | 2 -- indra/newview/llpanelgroupnotices.cpp | 7 ---- indra/newview/llpanelprofile.cpp | 46 +++++++++++++++++++++++++++ indra/newview/llpanelprofile.h | 6 ++++ 5 files changed, 52 insertions(+), 14 deletions(-) diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index ff33efe4aa..e3d887d943 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -39,11 +39,6 @@ LLProfileDropTarget::LLProfileDropTarget(const LLProfileDropTarget::Params& p) mAgentID(p.agent_id) {} -void LLProfileDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) -{ - LL_INFOS() << "LLProfileDropTarget::doDrop()" << LL_ENDL; -} - BOOL LLProfileDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index f182660c8e..bfde921df0 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -59,8 +59,6 @@ public: LLProfileDropTarget(const Params&); ~LLProfileDropTarget() {} - void doDrop(EDragAndDropType cargo_type, void* cargo_data); - // // LLView functionality virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 82f880c9ee..54121c2656 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -89,8 +89,6 @@ public: LLGroupDropTarget(const Params&); ~LLGroupDropTarget() {}; - void doDrop(EDragAndDropType cargo_type, void* cargo_data); - // // LLView functionality virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, @@ -114,11 +112,6 @@ LLGroupDropTarget::LLGroupDropTarget(const LLGroupDropTarget::Params& p) mGroupID(p.group_id) {} -void LLGroupDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) -{ - LL_INFOS() << "LLGroupDropTarget::doDrop()" << LL_ENDL; -} - BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index c2c9139c19..24091644e3 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -46,6 +46,7 @@ #include "lltexteditor.h" #include "lltexturectrl.h" #include "lltoggleablemenu.h" +#include "lltooldraganddrop.h" #include "llgrouplist.h" #include "llurlaction.h" @@ -998,6 +999,51 @@ void LLPanelProfileSecondLife::onOpen(const LLSD& key) mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCache, this, _1, _2)); } + +BOOL LLPanelProfileSecondLife::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + // Try children first + if (LLPanelProfileTab::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) + && *accept != ACCEPT_NO) + { + return TRUE; + } + + // No point sharing with own profile + if (getSelfProfile()) + { + return FALSE; + } + + // Exclude fields that look like they are editable. + S32 child_x = 0; + S32 child_y = 0; + if (localPointToOtherView(x, y, &child_x, &child_y, mDescriptionEdit) + && mDescriptionEdit->pointInView(child_x, child_y)) + { + return FALSE; + } + + if (localPointToOtherView(x, y, &child_x, &child_y, mGroupList) + && mGroupList->pointInView(child_x, child_y)) + { + return FALSE; + } + + // Share + LLToolDragAndDrop::handleGiveDragAndDrop(getAvatarId(), + LLUUID::null, + drop, + cargo_type, + cargo_data, + accept); + return TRUE; +} + void LLPanelProfileSecondLife::updateData() { LLUUID avatar_id = getAvatarId(); diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index 11632a10ae..45655cd67b 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -78,6 +78,12 @@ public: void onOpen(const LLSD& key) override; + BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) override; + /** * LLFriendObserver trigger */ From ce75d0e63b5b0efa1f5e880ee029f95aed56f66d Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 6 Dec 2023 19:30:48 +0000 Subject: [PATCH 03/29] SL-20635 - adde::qd new data to ObjectUpdate message containing num attachments or child prims --- indra/newview/llviewerobject.cpp | 331 ++++++++++--------------------- indra/newview/llviewerobject.h | 2 - 2 files changed, 107 insertions(+), 226 deletions(-) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 2bcd0858d3..735b3c03b7 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -1159,6 +1159,20 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, LL_DEBUGS("ObjectUpdate") << " mesgsys " << mesgsys << " dp " << dp << " id " << getID() << " update_type " << (S32) update_type << LL_ENDL; dumpStack("ObjectUpdateStack"); + // The new OBJECTDATA_FIELD_SIZE_124, OBJECTDATA_FIELD_SIZE_140, OBJECTDATA_FIELD_SIZE_80 + // and OBJECTDATA_FIELD_SIZE_64 lengths should be supported in the existing cases below. + // Each case should start at the beginning of the buffer and extract all known + // values, and ignore any unknown data at the end of the buffer. + // This allows new data in the future without breaking current viewers. + const S32 OBJECTDATA_FIELD_SIZE_140 = 140; // Full precision avatar update for future extended data + const S32 OBJECTDATA_FIELD_SIZE_124 = 124; // Full precision object update for future extended data + const S32 OBJECTDATA_FIELD_SIZE_76 = 76; // Full precision avatar update + const S32 OBJECTDATA_FIELD_SIZE_60 = 60; // Full precision object update + const S32 OBJECTDATA_FIELD_SIZE_80 = 80; // Terse avatar update, 16 bit precision for future extended data + const S32 OBJECTDATA_FIELD_SIZE_64 = 64; // Terse object update, 16 bit precision for future extended data + const S32 OBJECTDATA_FIELD_SIZE_48 = 48; // Terse avatar update, 16 bit precision + const S32 OBJECTDATA_FIELD_SIZE_32 = 32; // Terse object update, 16 bit precision + U32 retval = 0x0; // If region is removed from the list it is also deleted. @@ -1206,7 +1220,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, U32 x, y; from_region_handle(region_handle, &x, &y); - LL_ERRS() << "Object has invalid region " << x << ":" << y << "!" << LL_ENDL; + LL_WARNS("UpdateFail") << "Object has invalid region " << x << ":" << y << "!" << LL_ENDL; return retval; } @@ -1233,8 +1247,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, const F32 size = LLWorld::getInstance()->getRegionWidthInMeters(); const F32 MAX_HEIGHT = LLWorld::getInstance()->getRegionMaxHeight(); const F32 MIN_HEIGHT = LLWorld::getInstance()->getRegionMinHeight(); - S32 length; - S32 count; + S32 length = 0; + S32 count = 0; S32 this_update_precision = 32; // in bits // Temporaries, because we need to compare w/ previous to set dirty flags... @@ -1295,6 +1309,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_Scale, new_scale, block_num ); length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num, MAX_OBJECT_BINARY_DATA_SIZE); + length = llmin(length, MAX_OBJECT_BINARY_DATA_SIZE); // getBinaryDataFast() safely fills the buffer to max_size mTotalCRC = crc; // Might need to update mSourceMuted here to properly pick up new radius @@ -1314,20 +1329,23 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } setClickAction(click_action); - count = 0; - LLVector4 collision_plane; - + count = 0; + LLVector4 collision_plane; + switch(length) { - case (60 + 16): + case OBJECTDATA_FIELD_SIZE_140: + case OBJECTDATA_FIELD_SIZE_76: // pull out collision normal for avatar htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); ((LLVOAvatar*)this)->setFootPlane(collision_plane); count += sizeof(LLVector4); - // fall through - case 60: + [[fallthrough]]; + + case OBJECTDATA_FIELD_SIZE_124: + case OBJECTDATA_FIELD_SIZE_60: this_update_precision = 32; - // this is a terse update + // this is a full precision update // pos htolememcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); count += sizeof(LLVector3); @@ -1352,117 +1370,21 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, resetRot(); } setAngularVelocity(new_angv); + count += sizeof(LLVector3); #if LL_DARWIN - if (length == 76) + if (length == OBJECTDATA_FIELD_SIZE_76 || + length == OBJECTDATA_FIELD_SIZE_140) { setAngularVelocity(LLVector3::zero); } #endif break; - case(32 + 16): - // pull out collision normal for avatar - htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); - ((LLVOAvatar*)this)->setFootPlane(collision_plane); - count += sizeof(LLVector4); - // fall through - case 32: - this_update_precision = 16; - test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); - // This is a terse 16 update, so treat data as an array of U16's. -#ifdef LL_BIG_ENDIAN - htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); - -#ifdef LL_BIG_ENDIAN - htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - setVelocity(LLVector3(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size))); - -#ifdef LL_BIG_ENDIAN - htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - setAcceleration(LLVector3(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size))); - -#ifdef LL_BIG_ENDIAN - htolememcpy(valswizzle, &data[count], MVT_U16Quat, 4); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*4; - new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); - new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); - new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); - new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); - -#ifdef LL_BIG_ENDIAN - htolememcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - new_angv.setVec(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size)); - if (new_angv.isExactlyZero()) - { - // reset rotation time - resetRot(); - } - setAngularVelocity(new_angv); - break; - - case 16: - this_update_precision = 8; - test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); - // this is a terse 8 update - new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT); - - setVelocity(U8_to_F32(data[3], -size, size), - U8_to_F32(data[4], -size, size), - U8_to_F32(data[5], -size, size) ); - - setAcceleration(U8_to_F32(data[6], -size, size), - U8_to_F32(data[7], -size, size), - U8_to_F32(data[8], -size, size) ); - - new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f); - new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f); - new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f); - new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f); - - new_angv.setVec(U8_to_F32(data[13], -size, size), - U8_to_F32(data[14], -size, size), - U8_to_F32(data[15], -size, size) ); - if (new_angv.isExactlyZero()) - { - // reset rotation time - resetRot(); - } - setAngularVelocity(new_angv); - break; + // length values 48, 32 and 16 were once in viewer code but + // are never sent by the SL simulator + default: + LL_WARNS("UpdateFail") << "Unexpected ObjectData buffer size " << length + << " for " << getID() << " with OUT_FULL message" << LL_ENDL; } //////////////////////////////////////////////////// @@ -1496,20 +1418,50 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, if (mData) { delete [] mData; - } + mData = NULL; + } - // Check for appended generic data - S32 data_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Data); - if (data_size <= 0) - { - mData = NULL; - } - else - { - // ...has generic data - mData = new U8[data_size]; - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, mData, data_size, block_num); - } + // Dec 2023 new generic data: + // Trees work as before, this field contains genome data + // Not a tree: + // avatars send 1 byte with the number of attachments + // root objects send 1 byte with the number of prims in the linkset + // If the generic data size is zero, then number of attachments or prims is zero + // + // Viewers should not match the data size exactly, but if the field has data, + // read the 1st byte as described above, and ignore the rest. + + // Check for appended generic data + const S32 GENERIC_DATA_BUFFER_SIZE = 16; + S32 data_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Data); + if (data_size > 0) + { // has generic data + if (getPCode() == LL_PCODE_LEGACY_TREE || getPCode() == LL_PCODE_TREE_NEW) + { + mData = new U8[data_size]; + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, mData, data_size, block_num); + LL_DEBUGS("NewObjectData") << "Read " << data_size << " bytes tree genome data for " << getID() << ", pcode " + << getPCodeString() << ", value " << (S32) mData[0] << LL_ENDL; + } + else + { // Extract number of prims or attachments + U8 generic_data[GENERIC_DATA_BUFFER_SIZE]; + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, + &generic_data[0], llmin(data_size, GENERIC_DATA_BUFFER_SIZE), block_num); + // This is sample code to extract the number of attachments or prims + // Future viewers should use it for their own purposes + if (isAvatar()) + { + LL_DEBUGS("NewObjectData") << "Avatar " << getID() << " has " + << (S32) generic_data[0] << " attachments" << LL_ENDL; + } + else + { + LL_DEBUGS("NewObjectData") << "Root prim " << getID() << " has " + << (S32) generic_data[0] << " prims in linkset" << LL_ENDL; + } + } + } S32 text_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Text); if (text_size > 1) @@ -1605,60 +1557,24 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, #endif length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num, MAX_OBJECT_BINARY_DATA_SIZE); - count = 0; + length = llmin(length, MAX_OBJECT_BINARY_DATA_SIZE); // getBinaryDataFast() safely fills the buffer to max_size + count = 0; LLVector4 collision_plane; - + switch(length) { - case(60 + 16): + case OBJECTDATA_FIELD_SIZE_80: + case OBJECTDATA_FIELD_SIZE_48: // pull out collision normal for avatar htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); ((LLVOAvatar*)this)->setFootPlane(collision_plane); count += sizeof(LLVector4); - // fall through - case 60: - // this is a terse 32 update - // pos - this_update_precision = 32; - htolememcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // vel - htolememcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // acc - htolememcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // theta - { - LLVector3 vec; - htolememcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - new_rot.unpackFromVector3(vec); - } - count += sizeof(LLVector3); - // omega - htolememcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - if (new_angv.isExactlyZero()) - { - // reset rotation time - resetRot(); - } - setAngularVelocity(new_angv); -#if LL_DARWIN - if (length == 76) - { - setAngularVelocity(LLVector3::zero); - } -#endif - break; - case(32 + 16): - // pull out collision normal for avatar - htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); - ((LLVOAvatar*)this)->setFootPlane(collision_plane); - count += sizeof(LLVector4); - // fall through - case 32: - // this is a terse 16 update - this_update_precision = 16; + [[fallthrough]]; + + case OBJECTDATA_FIELD_SIZE_64: + case OBJECTDATA_FIELD_SIZE_32: + // this is a terse 16 bit quantized update + this_update_precision = 16; test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); #ifdef LL_BIG_ENDIAN @@ -1718,33 +1634,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, setAngularVelocity(new_angv); break; - case 16: - // this is a terse 8 update - this_update_precision = 8; - test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); - new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT); - - setVelocity(U8_to_F32(data[3], -size, size), - U8_to_F32(data[4], -size, size), - U8_to_F32(data[5], -size, size) ); - - setAcceleration(U8_to_F32(data[6], -size, size), - U8_to_F32(data[7], -size, size), - U8_to_F32(data[8], -size, size) ); - - new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f); - new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f); - new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f); - new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f); - - new_angv.set(U8_to_F32(data[13], -size, size), - U8_to_F32(data[14], -size, size), - U8_to_F32(data[15], -size, size) ); - setAngularVelocity(new_angv); - break; - } + // Previous viewers had code for length 76, 60 or 16 byte length + // with full precision or 8 bit quanitzation, but the + // SL servers will never send those data formats. If you ever see this + // warning on a SL server, please file a bug report + default: + LL_WARNS("UpdateFail") << "Unexpected ObjectData buffer size " << length << " for " << getID() + << " with OUT_FULL message" << LL_ENDL; + } U8 state; mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); @@ -1753,13 +1650,13 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } default: + LL_WARNS("UpdateFail") << "Unknown uncompressed update type " << update_type << " for " << getID() << LL_ENDL; break; - } } else { - // handle the compressed case + // handle the compressed case - have dp datapacker LLUUID sound_uuid; LLUUID owner_id; F32 gain = 0; @@ -2013,6 +1910,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, break; default: + LL_WARNS("UpdateFail") << "Unknown compressed update type " << update_type << " for " << getID() << LL_ENDL; break; } } @@ -2060,7 +1958,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, if (sent_parentp && sent_parentp->getParent() == this) { // Try to recover if we attempt to attach a parent to its child - LL_WARNS() << "Attempt to attach a parent to it's child: " << this->getID() << " to " << sent_parentp->getID() << LL_ENDL; + LL_WARNS("UpdateFail") << "Attempt to attach a parent to it's child: " << this->getID() << " to " + << sent_parentp->getID() << LL_ENDL; this->removeChild(sent_parentp); sent_parentp->setDrawableParent(NULL); } @@ -2084,7 +1983,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { if (mDrawable->isDead() || !mDrawable->getVObj()) { - LL_WARNS() << "Drawable is dead or no VObj!" << LL_ENDL; + LL_WARNS("UpdateFail") << "Drawable is dead or no VObj!" << LL_ENDL; sent_parentp->addChild(this); } else @@ -2094,9 +1993,9 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Bad, we got a cycle somehow. // Kill both the parent and the child, and // set cache misses for both of them. - LL_WARNS() << "Attempting to recover from parenting cycle!" << LL_ENDL; - LL_WARNS() << "Killing " << sent_parentp->getID() << " and " << getID() << LL_ENDL; - LL_WARNS() << "Adding to cache miss list" << LL_ENDL; + LL_WARNS("UpdateFail") << "Attempting to recover from parenting cycle! " + << "Killing " << sent_parentp->getID() << " and " << getID() + << ", Adding to cache miss list" << LL_ENDL; setParent(NULL); sent_parentp->setParent(NULL); getRegion()->addCacheMissFull(getLocalID()); @@ -2751,22 +2650,6 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& frame_tim -BOOL LLViewerObject::setData(const U8 *datap, const U32 data_size) -{ - delete [] mData; - - if (datap) - { - mData = new U8[data_size]; - if (!mData) - { - return FALSE; - } - memcpy(mData, datap, data_size); /* Flawfinder: ignore */ - } - return TRUE; -} - // delete an item in the inventory, but don't tell the server. This is // used internally by remove, update, and savescript. // This will only delete the first item with an item_id in the list diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 80da7b2f73..b85dcc5da2 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -779,8 +779,6 @@ protected: static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0); - BOOL setData(const U8 *datap, const U32 data_size); - // Hide or show HUD, icon and particles void hideExtraDisplayItems( BOOL hidden ); From 01a083ea647c2defcf7eace823f74f85321c97c5 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 8 Dec 2023 01:58:24 +0200 Subject: [PATCH 04/29] SL-20672 Support marketplace in gallery view --- indra/newview/llinventorygallerymenu.cpp | 127 +++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 5f4b816b99..647f3c9ec4 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -295,6 +295,54 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata) preview_texture->saveAs(); } } + else if (("copy_to_marketplace_listings" == action) + || ("move_to_marketplace_listings" == action)) + { + LLViewerInventoryItem* itemp = gInventory.getItem(mUUIDs.front()); + bool copy_operation = "copy_to_marketplace_listings" == action; + bool can_copy = itemp ? itemp->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) : false; + + + if (can_copy) + { + const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + if (itemp) + { + move_item_to_marketplacelistings(itemp, marketplacelistings_id, copy_operation); + } + } + else + { + uuid_vec_t lamdba_list = mUUIDs; + LLNotificationsUtil::add( + "ConfirmCopyToMarketplace", + LLSD(), + LLSD(), + [lamdba_list](const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + // option == 0 Move no copy item(s) + // option == 1 Don't move no copy item(s) (leave them behind) + bool copy_and_move = option == 0; + const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + + // main inventory only allows one item? + LLViewerInventoryItem* itemp = gInventory.getItem(lamdba_list.front()); + if (itemp) + { + if (itemp->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + move_item_to_marketplacelistings(itemp, marketplacelistings_id, true); + } + else if (copy_and_move) + { + move_item_to_marketplacelistings(itemp, marketplacelistings_id, false); + } + } + } + ); + } + } } void LLInventoryGalleryContextMenu::rename(const LLUUID& item_id) @@ -388,6 +436,44 @@ bool is_inbox_folder(LLUUID item_id) return gInventory.isObjectDescendentOf(item_id, inbox_id); } +bool can_list_on_marketplace(const LLUUID &id) +{ + const LLInventoryObject* obj = gInventory.getObject(id); + bool can_list = (obj != NULL); + + if (can_list) + { + const LLUUID& object_id = obj->getLinkedUUID(); + can_list = object_id.notNull(); + + if (can_list) + { + std::string error_msg; + const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + if (marketplacelistings_id.notNull()) + { + LLViewerInventoryCategory* master_folder = gInventory.getCategory(marketplacelistings_id); + LLInventoryCategory* cat = gInventory.getCategory(id); + if (cat) + { + can_list = can_move_folder_to_marketplace(master_folder, master_folder, cat, error_msg); + } + else + { + LLInventoryItem* item = gInventory.getItem(id); + can_list = (item ? can_move_item_to_marketplace(master_folder, master_folder, item, error_msg) : false); + } + } + else + { + can_list = false; + } + } + } + + return can_list; +} + void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* menu) { LLUUID selected_id = mUUIDs.front(); @@ -707,6 +793,47 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men disabled_items.push_back(std::string("New Folder")); disabled_items.push_back(std::string("upload_def")); } + + // Marketplace + bool can_list = false; + const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + if (marketplacelistings_id.notNull() && !is_inbox && !obj->getIsLinkType()) + { + if (is_folder) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id); + if (cat + && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) + && gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID())) + { + can_list = true; + } + } + else + { + LLViewerInventoryItem* item = gInventory.getItem(selected_id); + if (item + && item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()) + && item->getPermissions().getOwner() != ALEXANDRIA_LINDEN_ID + && LLAssetType::AT_CALLINGCARD != item->getType()) + { + can_list = true; + } + } + } + + if (can_list) + { + items.push_back(std::string("Marketplace Separator")); + items.push_back(std::string("Marketplace Copy")); + items.push_back(std::string("Marketplace Move")); + + if (!can_list_on_marketplace(selected_id)) + { + disabled_items.push_back(std::string("Marketplace Copy")); + disabled_items.push_back(std::string("Marketplace Move")); + } + } } hide_context_entries(*menu, items, disabled_items); From 3777dbb3d6ed9b3411eef71c10182afed19c974b Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 8 Dec 2023 23:57:40 +0000 Subject: [PATCH 05/29] More sl-20635 - moved new attachment data to AvatarAppearance message --- indra/llmessage/message.cpp | 3 +++ indra/newview/llvoavatar.cpp | 21 +++++++++++++++++++-- scripts/messages/message_template.msg | 5 +++++ scripts/messages/message_template.msg.sha1 | 2 +- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 31acc65642..5de29ba66f 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -307,12 +307,15 @@ void LLMessageSystem::loadTemplateFile(const std::string& filename, bool failure LLTemplateTokenizer tokens(template_body); LLTemplateParser parsed(tokens); mMessageFileVersionNumber = parsed.getVersion(); + S32 count = 0; for(LLTemplateParser::message_iterator iter = parsed.getMessagesBegin(); iter != parsed.getMessagesEnd(); iter++) { addTemplate(*iter); + count++; } + LL_INFOS("Messaging") << "Read " << count << " messages from " << filename << LL_ENDL; } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 35e45c6cd9..2ddd174ba7 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -9266,7 +9266,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe //mesgsys->getU32Fast(_PREHASH_AppearanceData, _PREHASH_Flags, appearance_flags, 0); } - // Parse the AppearanceData field, if any. + // Parse the AppearanceHover field, if any. contents.mHoverOffsetWasSet = false; if (mesgsys->has(_PREHASH_AppearanceHover)) { @@ -9276,7 +9276,24 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe contents.mHoverOffset = hover; contents.mHoverOffsetWasSet = true; } - + + // Get attachment info, if sent + LLUUID attachment_id; + U8 attach_point; + S32 attach_count = mesgsys->getNumberOfBlocksFast(_PREHASH_AttachmentBlock); + LL_DEBUGS("AVAppearanceAttachments") << "Agent " << getID() << " has " + << attach_count << " attachments" << LL_ENDL; + + for (S32 attach_i = 0; attach_i < attach_count; attach_i++) + { + mesgsys->getUUIDFast(_PREHASH_AttachmentBlock, _PREHASH_ID, attachment_id, attach_i); + mesgsys->getU8Fast(_PREHASH_AttachmentBlock, _PREHASH_AttachmentPoint, attach_point, attach_i); + LL_DEBUGS("AVAppearanceAttachments") << "AV " << getID() << " has attachment " << attach_i << " " + << (attachment_id.isNull() ? "pending" : attachment_id.asString()) + << " on point " << (S32)attach_point << LL_ENDL; + // To do - store and use this information as needed + } + // Parse visual params, if any. S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam); static LLCachedControl block_some_avatars(gSavedSettings, "BlockSomeAvatarAppearanceVisualParams"); diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg index c019a76793..1450c111c2 100755 --- a/scripts/messages/message_template.msg +++ b/scripts/messages/message_template.msg @@ -3607,6 +3607,11 @@ version 2.0 AppearanceHover Variable { HoverHeight LLVector3 } } + { + AttachmentBlock Variable + { ID LLUUID } + { AttachmentPoint U8 } + } } // AvatarSitResponse - response to a request to sit on an object diff --git a/scripts/messages/message_template.msg.sha1 b/scripts/messages/message_template.msg.sha1 index 5ad85458e9..efa5f3cf48 100755 --- a/scripts/messages/message_template.msg.sha1 +++ b/scripts/messages/message_template.msg.sha1 @@ -1 +1 @@ -e3bd0529a647d938ab6d48f26d21dd52c07ebc6e \ No newline at end of file +d7915d67467e59287857630bd89bf9529d065199 \ No newline at end of file From d4c3300f9b81296f765c83c1e822251e86d91925 Mon Sep 17 00:00:00 2001 From: simon Date: Mon, 11 Dec 2023 17:30:49 +0000 Subject: [PATCH 06/29] sl-20635 - cleaned up code after reading it yet again --- indra/newview/llviewerobject.cpp | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 735b3c03b7..c5d4c6dc09 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -1423,13 +1423,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Dec 2023 new generic data: // Trees work as before, this field contains genome data - // Not a tree: - // avatars send 1 byte with the number of attachments - // root objects send 1 byte with the number of prims in the linkset - // If the generic data size is zero, then number of attachments or prims is zero + // Not a tree: root objects send 1 byte with the number of + // total prims in the linkset + // If the generic data size is zero, then number of prims is 1 // - // Viewers should not match the data size exactly, but if the field has data, - // read the 1st byte as described above, and ignore the rest. + // Viewers should not check for specific data sizes exactly, but if + // the field has data, process it from the start and ignore the remainder. // Check for appended generic data const S32 GENERIC_DATA_BUFFER_SIZE = 16; @@ -1444,21 +1443,17 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, << getPCodeString() << ", value " << (S32) mData[0] << LL_ENDL; } else - { // Extract number of prims or attachments + { // Extract number of prims U8 generic_data[GENERIC_DATA_BUFFER_SIZE]; mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, &generic_data[0], llmin(data_size, GENERIC_DATA_BUFFER_SIZE), block_num); - // This is sample code to extract the number of attachments or prims + // This is sample code to extract the number of prims // Future viewers should use it for their own purposes - if (isAvatar()) - { - LL_DEBUGS("NewObjectData") << "Avatar " << getID() << " has " - << (S32) generic_data[0] << " attachments" << LL_ENDL; - } - else + if (!isAvatar()) { + S32 num_prims = (S32) generic_data[0]; LL_DEBUGS("NewObjectData") << "Root prim " << getID() << " has " - << (S32) generic_data[0] << " prims in linkset" << LL_ENDL; + << num_prims << " prims in linkset" << LL_ENDL; } } } @@ -1637,7 +1632,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Previous viewers had code for length 76, 60 or 16 byte length // with full precision or 8 bit quanitzation, but the // SL servers will never send those data formats. If you ever see this - // warning on a SL server, please file a bug report + // warning in Second Life, please file a bug report default: LL_WARNS("UpdateFail") << "Unexpected ObjectData buffer size " << length << " for " << getID() << " with OUT_FULL message" << LL_ENDL; From 3b99af03ca5774bd817c803842eecfc205f77afd Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 8 Dec 2023 23:19:37 +0200 Subject: [PATCH 07/29] SL-20672 Item and folder creation support Moving everything manually doesn't seem like a right way, probably need to make LLFolderView draw grids and then relace with LLInventoryPanel --- indra/newview/llinventorybridge.cpp | 6 - indra/newview/llinventorygallery.cpp | 33 +++ indra/newview/llinventorygallery.h | 1 + indra/newview/llinventorygallerymenu.cpp | 73 +++++- indra/newview/llpanelmaininventory.cpp | 1 + .../default/xui/en/menu_gallery_inventory.xml | 228 ++++++++++++++++++ 6 files changed, 325 insertions(+), 17 deletions(-) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index cb5316ddf4..40e0c66c23 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -4359,12 +4359,10 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items if (!isInboxFolder() // don't allow creation in inbox && outfits_id != mUUID) { - bool menu_items_added = false; // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) { items.push_back(std::string("New Folder")); - menu_items_added = true; } if (!isMarketplaceListingsFolder()) { @@ -4381,10 +4379,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items { disabled_items.push_back("New Settings"); } - } - if (menu_items_added) - { - items.push_back(std::string("Create Separator")); } } getClipboardEntries(false, items, disabled_items, flags); diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index 62180bb066..97b82a581c 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -2010,6 +2010,39 @@ void LLInventoryGallery::pasteAsLink(const LLUUID& dest, } } +void LLInventoryGallery::doCreate(const LLUUID& dest, const LLSD& userdata) +{ + + LLViewerInventoryCategory* cat = gInventory.getCategory(dest); + if (cat && mFolderID != dest) + { + menu_create_inventory_item(NULL, dest, userdata, LLUUID::null); + } + else + { + // todo: needs to reset current floater's filter, + // like reset_inventory_filter() + + LLHandle handle = getHandle(); + std::function callback_cat_created = + [handle](const LLUUID& new_id) + { + gInventory.notifyObservers(); + LLInventoryGallery* panel = static_cast(handle.get()); + if (panel && new_id.notNull()) + { + panel->clearSelection(); + if (panel->mItemMap.count(new_id) != 0) + { + panel->addItemSelection(new_id, true); + } + } + }; + + menu_create_inventory_item(NULL, mFolderID, userdata, LLUUID::null, callback_cat_created); + } +} + void LLInventoryGallery::claimEditHandler() { gEditMenuHandler = this; diff --git a/indra/newview/llinventorygallery.h b/indra/newview/llinventorygallery.h index 9b3f12701f..95df9eeb69 100644 --- a/indra/newview/llinventorygallery.h +++ b/indra/newview/llinventorygallery.h @@ -165,6 +165,7 @@ public: void deleteSelection(); bool canDeleteSelection(); void pasteAsLink(); + void doCreate(const LLUUID& dest, const LLSD& userdata); void setSortOrder(U32 order, bool update = false); U32 getSortOrder() { return mSortOrder; }; diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 647f3c9ec4..def66c8968 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -32,9 +32,11 @@ #include "llappearancemgr.h" #include "llavataractions.h" #include "llclipboard.h" +#include "llenvironment.h" #include "llfloaterreg.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterworldmap.h" +#include "llfriendcard.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" #include "llinventorymodel.h" @@ -57,11 +59,33 @@ LLContextMenu* LLInventoryGalleryContextMenu::createMenu() registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2)); registrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH)); registrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND)); + registrar.add("Inventory.DoCreate", [this](LLUICtrl*, const LLSD& data) + { + if (mRootFolder) + { + mGallery->doCreate(mGallery->getRootFolder(), data); + } + else + { + mGallery->doCreate(mUUIDs.front(), data); + } + }); std::set uuids(mUUIDs.begin(), mUUIDs.end()); 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.EnvironmentEnabled", [](LLUICtrl*, const LLSD&) + { + return LLEnvironment::instance().isInventoryEnabled(); + }); + enable_registrar.add("Inventory.MaterialsEnabled", [](LLUICtrl*, const LLSD&) + { + std::string agent_url = gAgent.getRegionCapability("UpdateMaterialAgentInventory"); + std::string task_url = gAgent.getRegionCapability("UpdateMaterialTaskInventory"); + + return (!agent_url.empty() && !task_url.empty()); + }); LLContextMenu* menu = createFromFile("menu_gallery_inventory.xml"); @@ -495,6 +519,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men bool is_in_trash = gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH)); bool is_lost_and_found = (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); bool is_outfits= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS)); + bool is_in_favorites = gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE)); //bool is_favorites= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE)); bool is_system_folder = false; @@ -589,11 +614,30 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men } else { + if (is_agent_inventory && !is_inbox && !is_cof && !is_in_favorites && !is_outfits) + { + LLViewerInventoryCategory* category = gInventory.getCategory(selected_id); + if (!category || !LLFriendCardsManager::instance().isCategoryInFriendFolder(category)) + { + items.push_back(std::string("New Folder")); + } + + items.push_back(std::string("create_new")); + items.push_back(std::string("New Script")); + items.push_back(std::string("New Note")); + items.push_back(std::string("New Gesture")); + items.push_back(std::string("New Material")); + items.push_back(std::string("New Clothes")); + items.push_back(std::string("New Body Parts")); + items.push_back(std::string("New Settings")); + } + if(can_share_item(selected_id)) { items.push_back(std::string("Share")); } - if (LLClipboard::instance().hasContents() && is_agent_inventory && !is_cof && !is_inbox_folder(selected_id)) + + if (LLClipboard::instance().hasContents() && is_agent_inventory && !is_cof && !is_inbox) { items.push_back(std::string("Paste")); @@ -605,7 +649,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men } if (is_folder && is_agent_inventory) { - if (!is_cof && (folder_type != LLFolderType::FT_OUTFIT) && !is_outfits && !is_inbox_folder(selected_id)) + if (!is_cof && (folder_type != LLFolderType::FT_OUTFIT) && !is_outfits && !is_inbox) { if (!gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD)) && !isRootFolder()) { @@ -792,6 +836,17 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men disabled_items.push_back(std::string("New Folder")); disabled_items.push_back(std::string("upload_def")); + disabled_items.push_back(std::string("create_new")); + } + + if (is_agent_inventory && !mRootFolder) + { + items.push_back(std::string("New folder from selected")); + items.push_back(std::string("Subfolder Separator")); + if (!is_only_items_selected(mUUIDs) && !is_only_cats_selected(mUUIDs)) + { + disabled_items.push_back(std::string("New folder from selected")); + } } // Marketplace @@ -809,16 +864,12 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men can_list = true; } } - else + else if (selected_item + && selected_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()) + && selected_item->getPermissions().getOwner() != ALEXANDRIA_LINDEN_ID + && LLAssetType::AT_CALLINGCARD != selected_item->getType()) { - LLViewerInventoryItem* item = gInventory.getItem(selected_id); - if (item - && item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()) - && item->getPermissions().getOwner() != ALEXANDRIA_LINDEN_ID - && LLAssetType::AT_CALLINGCARD != item->getType()) - { - can_list = true; - } + can_list = true; } } diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 20241aac24..a5a768776a 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -56,6 +56,7 @@ #include "lltrans.h" #include "llviewermenu.h" #include "llviewertexturelist.h" +#include "llviewerinventory.h" #include "llsidepanelinventory.h" #include "llfolderview.h" #include "llradiogroup.h" 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 d82c453e5f..feaba45cf8 100644 --- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml @@ -426,6 +426,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Thu, 14 Dec 2023 01:19:24 +0200 Subject: [PATCH 08/29] SL-20672 Added outfit related menu options to gallery --- indra/newview/llinventorygallerymenu.cpp | 106 +++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index def66c8968..f653641bb2 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -50,6 +50,41 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" + +void modify_outfit(BOOL append, const LLUUID& cat_id, LLInventoryModel* model) +{ + LLViewerInventoryCategory* cat = model->getCategory(cat_id); + if (!cat) return; + + // checking amount of items to wear + static LLCachedControl max_items(gSavedSettings, "WearFolderLimit", 125); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); + model->collectDescendentsIf(cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + not_worn); + + if (items.size() > max_items()) + { + LLSD args; + args["AMOUNT"] = llformat("%d", max_items); + LLNotificationsUtil::add("TooManyWearables", args); + return; + } + if (model->isObjectDescendentOf(cat_id, gInventory.getRootFolderID())) + { + LLAppearanceMgr::instance().wearInventoryCategory(cat, FALSE, append); + } + else + { + // Library, we need to copy content first + LLAppearanceMgr::instance().wearInventoryCategory(cat, TRUE, append); + } +} + LLContextMenu* LLInventoryGalleryContextMenu::createMenu() { LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; @@ -210,6 +245,22 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata) { ungroup_folder_items(mUUIDs.front()); } + else if ("replaceoutfit" == action) + { + modify_outfit(FALSE, mUUIDs.front(), &gInventory); + } + else if ("addtooutfit" == action) + { + modify_outfit(TRUE, mUUIDs.front(), &gInventory); + } + else if ("removefromoutfit" == action) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(mUUIDs.front()); + if (cat) + { + LLAppearanceMgr::instance().takeOffOutfit(cat->getLinkedUUID()); + } + } else if ("take_off" == action || "detach" == action) { for (LLUUID& selected_id : mUUIDs) @@ -498,6 +549,18 @@ bool can_list_on_marketplace(const LLUUID &id) return can_list; } +bool check_folder_for_contents_of_type(const LLUUID &id, LLInventoryModel* model, LLInventoryCollectFunctor& is_type) +{ + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + model->collectDescendentsIf(id, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_type); + return item_array.size() > 0; +} + void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* menu) { LLUUID selected_id = mUUIDs.front(); @@ -567,6 +630,49 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men items.push_back(std::string("open_in_new_window")); items.push_back(std::string("Open Folder Separator")); } + + // wearables related functionality for folders. + LLFindWearables is_wearable; + LLIsType is_object(LLAssetType::AT_OBJECT); + LLIsType is_gesture(LLAssetType::AT_GESTURE); + + if (check_folder_for_contents_of_type(selected_id, &gInventory, is_wearable) + || check_folder_for_contents_of_type(selected_id, &gInventory, is_object) + || check_folder_for_contents_of_type(selected_id, &gInventory, is_gesture)) + { + // Only enable add/replace outfit for non-system folders. + if (!is_system_folder) + { + // Adding an outfit onto another (versus replacing) doesn't make sense. + if (folder_type != LLFolderType::FT_OUTFIT) + { + items.push_back(std::string("Add To Outfit")); + if (!LLAppearanceMgr::instance().getCanAddToCOF(selected_id)) + { + disabled_items.push_back(std::string("Add To Outfit")); + } + } + + items.push_back(std::string("Replace Outfit")); + if (!LLAppearanceMgr::instance().getCanReplaceCOF(selected_id)) + { + disabled_items.push_back(std::string("Replace Outfit")); + } + } + if (is_agent_inventory) + { + items.push_back(std::string("Folder Wearables Separator")); + // Note: If user tries to unwear "My Inventory", it's going to deactivate everything including gestures + // Might be safer to disable this for "My Inventory" + items.push_back(std::string("Remove From Outfit")); + if (folder_type != LLFolderType::FT_ROOT_INVENTORY // Unless COF is empty, whih shouldn't be, warrantied to have worn items + && !LLAppearanceMgr::getCanRemoveFromCOF(selected_id)) // expensive from root! + { + disabled_items.push_back(std::string("Remove From Outfit")); + } + } + items.push_back(std::string("Outfit Separator")); + } } else { From 7f9438ed2b1e91aff615673ca2d97a3f300910f6 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 14 Dec 2023 23:25:11 +0100 Subject: [PATCH 09/29] SL-3508 Crash in LLKDUDecodeState::processTileDecode --- indra/llimage/llimage.cpp | 4 ++++ indra/llimage/llimagej2c.cpp | 14 +++++++++++--- indra/llkdu/llimagej2ckdu.cpp | 9 ++++++--- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 031471d1fe..7ac80825b5 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -2130,6 +2130,10 @@ U8* LLImageFormatted::reallocateData(S32 size) // virtual void LLImageFormatted::deleteData() { + if (mDecoding) + { + LL_ERRS() << "LLImageFormatted::deleteData() is called during decoding" << LL_ENDL; + } sGlobalFormattedMemory -= getDataSize(); LLImageBase::deleteData(); } diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 8dba1641a6..a4957466d4 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -157,10 +157,10 @@ bool LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LLTimer elapsed; - bool res = true; - resetLastError(); + mDecoding = true; + bool res; // Check to make sure that this instance has been initialized with data if (!getData() || (getDataSize() < 16)) { @@ -171,7 +171,6 @@ bool LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir { // Update the raw discard level updateRawDiscardLevel(); - mDecoding = true; res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); } @@ -181,12 +180,21 @@ bool LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir { // Failed raw_imagep->deleteData(); + res = false; } else { mDecoding = false; } } + else + { + if (mDecoding) + { + LL_WARNS() << "decodeImpl failed but mDecoding is TRUE" << LL_ENDL; + mDecoding = false; + } + } if (!mLastError.empty()) { diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 2ad42d6b87..eeda08f21e 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -514,6 +514,7 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; ECodeStreamMode mode = MODE_FAST; + bool limit_time = decode_time > 0.0f; LLTimer decode_timer; if (!mCodeStreamp->exists()) @@ -578,16 +579,18 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco mCodeStreamp.get())); } // Do the actual processing - F32 remaining_time = decode_time - decode_timer.getElapsedTimeF32(); + F32 remaining_time = limit_time ? decode_time - decode_timer.getElapsedTimeF32() : 0.0f; // This is where we do the actual decode. If we run out of time, return false. - if (mDecodeState->processTileDecode(remaining_time, (decode_time > 0.0f))) + if (mDecodeState->processTileDecode(remaining_time, limit_time)) { mDecodeState.reset(); } else { // Not finished decoding yet. - // setLastError("Ran out of time while decoding"); + base.setLastError("Ran out of time while decoding"); + base.decodeFailed(); + cleanupCodeStream(); return false; } } From 3954e5d802d29009abdc8a58438cea333df632a3 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Fri, 15 Dec 2023 09:03:52 +0200 Subject: [PATCH 10/29] DRTVWR-600 macos buildfix --- indra/llkdu/llimagej2ckdu.cpp | 2 +- indra/newview/llinventorygallerymenu.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index eeda08f21e..d96cd105dd 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -579,7 +579,7 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco mCodeStreamp.get())); } // Do the actual processing - F32 remaining_time = limit_time ? decode_time - decode_timer.getElapsedTimeF32() : 0.0f; + F32 remaining_time = limit_time ? static_cast(decode_time - decode_timer.getElapsedTimeF32()) : 0.0f; // This is where we do the actual decode. If we run out of time, return false. if (mDecodeState->processTileDecode(remaining_time, limit_time)) { diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index f653641bb2..c8ac73b838 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -70,7 +70,7 @@ void modify_outfit(BOOL append, const LLUUID& cat_id, LLInventoryModel* model) if (items.size() > max_items()) { LLSD args; - args["AMOUNT"] = llformat("%d", max_items); + args["AMOUNT"] = llformat("%d", static_cast(max_items)); LLNotificationsUtil::add("TooManyWearables", args); return; } From e104f7ce0291ed1f7ab170714e319408bf076221 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 20 Dec 2023 17:41:03 +0100 Subject: [PATCH 11/29] DRTVWR-600 windows build fix --- indra/newview/llmaterialeditor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index a5437f7a88..5e78e15c72 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -2131,7 +2131,7 @@ bool LLMaterialEditor::canModifyObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_MODIFY}), permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_MODIFY}), permissions, item_out); } bool LLMaterialEditor::canSaveObjectsMaterial() @@ -2139,7 +2139,7 @@ bool LLMaterialEditor::canSaveObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item_out); } bool LLMaterialEditor::canClipboardObjectsMaterial() @@ -2165,7 +2165,7 @@ bool LLMaterialEditor::canClipboardObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), permissions, item_out); } void LLMaterialEditor::saveObjectsMaterialAs() @@ -2173,7 +2173,7 @@ void LLMaterialEditor::saveObjectsMaterialAs() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item = nullptr; - bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item); + bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item); if (!allowed) { LL_WARNS("MaterialEditor") << "Failed to save GLTF material from object" << LL_ENDL; From 74c8b028d42a8c5b080bb861e427f38cedd4ad7c Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Fri, 15 Dec 2023 18:26:14 +0100 Subject: [PATCH 12/29] SL-20743 Use LLMutex in LLImageBase for internal data thread-safety --- indra/llappearance/llavatarappearance.h | 2 +- indra/llappearance/llpolymorph.cpp | 4 +- indra/llappearance/llpolymorph.h | 4 +- indra/llappearance/lltexlayer.cpp | 2 +- indra/llappearance/lltexlayer.h | 2 +- indra/llcommon/llapr.cpp | 2 +- indra/llcommon/llapr.h | 2 +- indra/llcommon/llmutex.cpp | 186 ++++++++++++++++++++++- indra/llcommon/llmutex.h | 79 +++++++++- indra/llimage/llimage.cpp | 131 ++++++++++++---- indra/llimage/llimage.h | 79 ++++++---- indra/llimage/llimagebmp.cpp | 20 ++- indra/llimage/llimagebmp.h | 8 +- indra/llimage/llimagedxt.cpp | 15 +- indra/llimage/llimagefilter.cpp | 4 +- indra/llimage/llimagej2c.cpp | 35 +++-- indra/llimage/llimagejpeg.cpp | 12 +- indra/llimage/llimagejpeg.h | 2 - indra/llimage/llimagepng.cpp | 8 + indra/llimage/llimagetga.cpp | 15 +- indra/llimage/llimageworker.cpp | 13 +- indra/llimage/llpngwrapper.cpp | 2 + indra/llimagej2coj/llimagej2coj.cpp | 8 + indra/llkdu/llimagej2ckdu.cpp | 10 +- indra/llrender/llcubemap.cpp | 3 + indra/llrender/llfontfreetype.cpp | 1 + indra/llrender/llimagegl.cpp | 2 + indra/newview/lldrawpoolbump.cpp | 8 +- indra/newview/llfasttimerview.cpp | 2 + indra/newview/llfloater360capture.cpp | 4 + indra/newview/llfloaterauction.cpp | 2 + indra/newview/llfloatercolorpicker.cpp | 2 + indra/newview/llfloaterimagepreview.cpp | 1 + indra/newview/llinventorygallerymenu.cpp | 2 +- indra/newview/llmaterialeditor.cpp | 2 + indra/newview/llmeshrepository.cpp | 20 ++- indra/newview/llnetmap.cpp | 2 + indra/newview/llsnapshotlivepreview.cpp | 10 +- indra/newview/lltexturecache.cpp | 11 +- indra/newview/lltexturecache.h | 2 +- indra/newview/lltexturefetch.cpp | 7 +- indra/newview/lltinygltfhelper.cpp | 9 +- indra/newview/llviewerassetupload.cpp | 2 + indra/newview/llviewerparceloverlay.cpp | 2 + indra/newview/llviewertexture.cpp | 3 + indra/newview/llviewertexturelist.cpp | 4 + indra/newview/llviewerwindow.cpp | 6 + indra/newview/llvoavatar.cpp | 4 +- indra/newview/llvoavatar.h | 2 +- indra/newview/llvosky.cpp | 4 +- indra/newview/llvosky.h | 2 + indra/newview/llvovolume.cpp | 6 +- indra/newview/llwebprofile.cpp | 4 +- 53 files changed, 634 insertions(+), 140 deletions(-) diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index e3444efcf6..787235b235 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -232,7 +232,7 @@ public: //-------------------------------------------------------------------- public: void addMaskedMorph(LLAvatarAppearanceDefines::EBakedTextureIndex index, LLVisualParam* morph_target, BOOL invert, std::string layer); - virtual void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES) = 0; + virtual void applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES) = 0; /** Rendering ** ** diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp index 965b999bd4..223b2b7f1c 100644 --- a/indra/llappearance/llpolymorph.cpp +++ b/indra/llappearance/llpolymorph.cpp @@ -659,7 +659,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) //----------------------------------------------------------------------------- // applyMask() //----------------------------------------------------------------------------- -void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert) +void LLPolyMorphTarget::applyMask(const U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert) { LLVector4a *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL; @@ -780,7 +780,7 @@ LLPolyVertexMask::~LLPolyVertexMask() //----------------------------------------------------------------------------- // generateMask() //----------------------------------------------------------------------------- -void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights) +void LLPolyVertexMask::generateMask(const U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights) { // RN debug output that uses Image Debugger (http://www.cs.unc.edu/~baxter/projects/imdebug/) // BOOL debugImg = FALSE; diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h index 29cd373636..954f01811a 100644 --- a/indra/llappearance/llpolymorph.h +++ b/indra/llappearance/llpolymorph.h @@ -84,7 +84,7 @@ public: LLPolyVertexMask(const LLPolyVertexMask& pOther); ~LLPolyVertexMask(); - void generateMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights); + void generateMask(const U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights); F32* getMorphMaskWeights(); @@ -170,7 +170,7 @@ public: /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh); /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); - void applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert); + void applyMask(const U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert); void addPendingMorphMask() { mNumMorphMasksPending++; } void applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton() diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index ff894eeed3..e426615f1c 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -528,7 +528,7 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, gGL.setSceneBlendType(LLRender::BT_ALPHA); } -void LLTexLayerSet::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components) +void LLTexLayerSet::applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components) { mAvatarAppearance->applyMorphMask(tex_data, width, height, num_components, mBakedTexIndex); } diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index 74b421d3ee..ff95d7f5e9 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -203,7 +203,7 @@ public: void renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target = nullptr, bool forceClear = false); BOOL isBodyRegion(const std::string& region) const; - void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components); + void applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components); BOOL isMorphValid() const; virtual void requestUpdate() = 0; void invalidateMorphMasks(); diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 575c524219..834b0e7a3a 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -571,7 +571,7 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb } //static -S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) +S32 LLAPRFile::writeEx(const std::string& filename, const void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) { LL_PROFILE_ZONE_SCOPED; apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 565d7cfb63..f5717ea75e 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -193,7 +193,7 @@ public: // Returns bytes read/written, 0 if read/write fails: static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); - static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append + static S32 writeEx(const std::string& filename, const void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append //******************************************************************************************************************************* }; diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 0273dd5970..f56c2d08a6 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -29,19 +29,20 @@ #include "llthread.h" #include "lltimer.h" -//============================================================================ +//--------------------------------------------------------------------- +// +// LLMutex +// LLMutex::LLMutex() : mCount(0) { } - LLMutex::~LLMutex() { } - void LLMutex::lock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD @@ -112,7 +113,7 @@ LLThread::id_t LLMutex::lockingThread() const bool LLMutex::trylock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if(isSelfLocked()) + if (isSelfLocked()) { //redundant lock mCount++; return true; @@ -135,19 +136,185 @@ bool LLMutex::trylock() return true; } -//============================================================================ +//--------------------------------------------------------------------- +// +// LLSharedMutex +// +LLSharedMutex::LLSharedMutex() +: mLockingThreads(2) // Reserve 2 slots in the map hash table +, mIsShared(false) +{ +} + +bool LLSharedMutex::isLocked() const +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + std::lock_guard lock(mLockMutex); + + return !mLockingThreads.empty(); +} + +bool LLSharedMutex::isThreadLocked() const +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + std::lock_guard lock(mLockMutex); + + const_iterator it = mLockingThreads.find(current_thread); + return it != mLockingThreads.end(); +} + +void LLSharedMutex::lockShared() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + + mLockMutex.lock(); + iterator it = mLockingThreads.find(current_thread); + if (it != mLockingThreads.end()) + { + it->second++; + } + else + { + // Acquire the mutex immediately if the mutex is not locked exclusively + // or enter a locking state if the mutex is already locked exclusively + mLockMutex.unlock(); + mSharedMutex.lock_shared(); + mLockMutex.lock(); + // Continue after acquiring the mutex + mLockingThreads.emplace(std::make_pair(current_thread, 1)); + mIsShared = true; + } + mLockMutex.unlock(); +} + +void LLSharedMutex::lockExclusive() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + + mLockMutex.lock(); + if (mLockingThreads.size() == 1 && mLockingThreads.begin()->first == current_thread) + { + mLockingThreads.begin()->second++; + } + else + { + // Acquire the mutex immediately if mLockingThreads is empty + // or enter a locking state if mLockingThreads is not empty + mLockMutex.unlock(); + mSharedMutex.lock(); + mLockMutex.lock(); + // Continue after acquiring the mutex (and possible quitting the locking state) + mLockingThreads.emplace(std::make_pair(current_thread, 1)); + mIsShared = false; + } + mLockMutex.unlock(); +} + +bool LLSharedMutex::trylockShared() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + std::lock_guard lock(mLockMutex); + + iterator it = mLockingThreads.find(current_thread); + if (it != mLockingThreads.end()) + { + it->second++; + } + else + { + if (!mSharedMutex.try_lock_shared()) + return false; + + mLockingThreads.emplace(std::make_pair(current_thread, 1)); + mIsShared = true; + } + + return true; +} + +bool LLSharedMutex::trylockExclusive() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + std::lock_guard lock(mLockMutex); + + if (mLockingThreads.size() == 1 && mLockingThreads.begin()->first == current_thread) + { + mLockingThreads.begin()->second++; + } + else + { + if (!mSharedMutex.try_lock()) + return false; + + mLockingThreads.emplace(std::make_pair(current_thread, 1)); + mIsShared = false; + } + + return true; +} + +void LLSharedMutex::unlockShared() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + std::lock_guard lock(mLockMutex); + + iterator it = mLockingThreads.find(current_thread); + if (it != mLockingThreads.end()) + { + if (it->second > 1) + { + it->second--; + } + else + { + mLockingThreads.erase(it); + mSharedMutex.unlock_shared(); + } + } +} + +void LLSharedMutex::unlockExclusive() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LLThread::id_t current_thread = LLThread::currentID(); + std::lock_guard lock(mLockMutex); + + iterator it = mLockingThreads.find(current_thread); + if (it != mLockingThreads.end()) + { + if (it->second > 1) + { + it->second--; + } + else + { + mLockingThreads.erase(it); + mSharedMutex.unlock(); + } + } +} + + +//--------------------------------------------------------------------- +// +// LLCondition +// LLCondition::LLCondition() : LLMutex() { } - LLCondition::~LLCondition() { } - void LLCondition::wait() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD @@ -168,7 +335,10 @@ void LLCondition::broadcast() } - +//--------------------------------------------------------------------- +// +// LLMutexTrylock +// LLMutexTrylock::LLMutexTrylock(LLMutex* mutex) : mMutex(mutex), mLocked(false) diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h index 0d70da6178..077f810d61 100644 --- a/indra/llcommon/llmutex.h +++ b/indra/llcommon/llmutex.h @@ -32,6 +32,8 @@ #include #include "mutex.h" +#include +#include #include //============================================================================ @@ -66,6 +68,45 @@ protected: #endif }; +//============================================================================ + +class LL_COMMON_API LLSharedMutex +{ +public: + LLSharedMutex(); + + bool isLocked() const; + bool isThreadLocked() const; + bool isShared() const { return mIsShared; } + + void lockShared(); + void lockExclusive(); + template void lock(); + template<> void lock() { lockShared(); } + template<> void lock() { lockExclusive(); } + + bool trylockShared(); + bool trylockExclusive(); + template bool trylock(); + template<> bool trylock() { return trylockShared(); } + template<> bool trylock() { return trylockExclusive(); } + + void unlockShared(); + void unlockExclusive(); + template void unlock(); + template<> void unlock() { unlockShared(); } + template<> void unlock() { unlockExclusive(); } + +private: + std::shared_mutex mSharedMutex; + mutable std::mutex mLockMutex; + std::unordered_map mLockingThreads; + bool mIsShared; + + using iterator = std::unordered_map::iterator; + using const_iterator = std::unordered_map::const_iterator; +}; + // Actually a condition/mutex pair (since each condition needs to be associated with a mutex). class LL_COMMON_API LLCondition : public LLMutex { @@ -81,27 +122,57 @@ protected: std::condition_variable mCond; }; +//============================================================================ + class LLMutexLock { public: LLMutexLock(LLMutex* mutex) { mMutex = mutex; - - if(mMutex) + + if (mMutex) mMutex->lock(); } + ~LLMutexLock() { - if(mMutex) + if (mMutex) mMutex->unlock(); } + private: LLMutex* mMutex; }; //============================================================================ +template +class LLSharedMutexLockTemplate +{ +public: + LLSharedMutexLockTemplate(LLSharedMutex* mutex) + : mSharedMutex(mutex) + { + if (mSharedMutex) + mSharedMutex->lock(); + } + + ~LLSharedMutexLockTemplate() + { + if (mSharedMutex) + mSharedMutex->unlock(); + } + +private: + LLSharedMutex* mSharedMutex; +}; + +using LLSharedMutexLock = LLSharedMutexLockTemplate; +using LLExclusiveMutexLock = LLSharedMutexLockTemplate; + +//============================================================================ + // Scoped locking class similar in function to LLMutexLock but uses // the trylock() method to conditionally acquire lock without // blocking. Caller resolves the resulting condition by calling @@ -127,6 +198,8 @@ private: bool mLocked; }; +//============================================================================ + /** * @class LLScopedLock * @brief Small class to help lock and unlock mutexes. diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 7ac80825b5..520d7b4fd9 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -614,7 +614,6 @@ const std::string& LLImage::getLastError() //static void LLImage::setLastError(const std::string& message) { - LLMutexLock m(sMutex); sLastErrorMessage = message; } @@ -754,7 +753,7 @@ U8* LLImageBase::reallocateData(S32 size) return mData; } -const U8* LLImageBase::getData() const +const U8* LLImageBase::getData() const { if(mBadBufferAllocation) { @@ -765,7 +764,7 @@ const U8* LLImageBase::getData() const return mData; } // read only -U8* LLImageBase::getData() +U8* LLImageBase::getData() { if(mBadBufferAllocation) { @@ -778,7 +777,7 @@ U8* LLImageBase::getData() bool LLImageBase::isBufferInvalid() const { - return mBadBufferAllocation || mData == NULL ; + return mBadBufferAllocation || mData == NULL; } void LLImageBase::setSize(S32 width, S32 height, S32 ncomponents) @@ -854,6 +853,8 @@ LLImageRaw::~LLImageRaw() // virtual U8* LLImageRaw::allocateData(S32 size) { + LLImageDataLock lock(this); + U8* res = LLImageBase::allocateData(size); return res; } @@ -861,12 +862,16 @@ U8* LLImageRaw::allocateData(S32 size) // virtual U8* LLImageRaw::reallocateData(S32 size) { + LLImageDataLock lock(this); + U8* res = LLImageBase::reallocateData(size); return res; } void LLImageRaw::releaseData() { + LLImageDataLock lock(this); + LLImageBase::setSize(0, 0, 0); LLImageBase::setDataAndSize(nullptr, 0); } @@ -874,11 +879,15 @@ void LLImageRaw::releaseData() // virtual void LLImageRaw::deleteData() { + LLImageDataLock lock(this); + LLImageBase::deleteData(); } void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components) -{ +{ + LLImageDataLock lock(this); + if(data == getData()) { return ; @@ -892,6 +901,8 @@ void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components) bool LLImageRaw::resize(U16 width, U16 height, S8 components) { + LLImageDataLock lock(this); + if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components) && !isBufferInvalid()) { return true; @@ -907,6 +918,8 @@ bool LLImageRaw::resize(U16 width, U16 height, S8 components) bool LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height, const U8 *data, U32 stride, bool reverse_y) { + LLImageDataLock lock(this); + if (!getData()) { return false; @@ -934,6 +947,9 @@ bool LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height, void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a) { llassert( getComponents() <= 4 ); + + LLImageDataLock lock(this); + // This is fairly bogus, but it'll do for now. if (isBufferInvalid()) { @@ -974,6 +990,8 @@ void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a) // Reverses the order of the rows in the image void LLImageRaw::verticalFlip() { + LLImageDataLock lock(this); + S32 row_bytes = getWidth() * getComponents(); llassert(row_bytes > 0); std::vector line_buffer(row_bytes); @@ -991,6 +1009,8 @@ void LLImageRaw::verticalFlip() bool LLImageRaw::optimizeAwayAlpha() { + LLImageDataLock lock(this); + if (getComponents() == 4) { U8* data = getData(); @@ -1028,6 +1048,8 @@ bool LLImageRaw::optimizeAwayAlpha() void LLImageRaw::expandToPowerOfTwo(S32 max_dim, bool scale_image) { + LLImageDataLock lock(this); + // Find new sizes S32 new_width = expandDimToPowerOfTwo(getWidth(), max_dim); S32 new_height = expandDimToPowerOfTwo(getHeight(), max_dim); @@ -1037,6 +1059,8 @@ void LLImageRaw::expandToPowerOfTwo(S32 max_dim, bool scale_image) void LLImageRaw::contractToPowerOfTwo(S32 max_dim, bool scale_image) { + LLImageDataLock lock(this); + // Find new sizes S32 new_width = contractDimToPowerOfTwo(getWidth(), MIN_IMAGE_SIZE); S32 new_height = contractDimToPowerOfTwo(getHeight(), MIN_IMAGE_SIZE); @@ -1086,6 +1110,8 @@ S32 LLImageRaw::contractDimToPowerOfTwo(S32 curr_dim, S32 min_dim) void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim) { + LLImageDataLock lock(this); + // Find new sizes S32 new_width = biasedDimToPowerOfTwo(getWidth(),max_dim); S32 new_height = biasedDimToPowerOfTwo(getHeight(),max_dim); @@ -1093,6 +1119,7 @@ void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim) scale( new_width, new_height ); } +// static // Calculates (U8)(255*(a/255.f)*(b/255.f) + 0.5f). Thanks, Jim Blinn! inline U8 LLImageRaw::fastFractionalMult( U8 a, U8 b ) { @@ -1101,10 +1128,13 @@ inline U8 LLImageRaw::fastFractionalMult( U8 a, U8 b ) } -void LLImageRaw::composite( LLImageRaw* src ) +void LLImageRaw::composite( const LLImageRaw* src ) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataSharedLock lockIn(src); + LLImageDataLock lockOut(this); + if (!validateSrcAndDst("LLImageRaw::composite", src, dst)) { return; @@ -1143,12 +1173,14 @@ void LLImageRaw::composite( LLImageRaw* src ) // Src and dst can be any size. Src has 4 components. Dst has 3 components. -void LLImageRaw::compositeScaled4onto3(LLImageRaw* src) +void LLImageRaw::compositeScaled4onto3(const LLImageRaw* src) { LL_INFOS() << "compositeScaled4onto3" << LL_ENDL; LLImageRaw* dst = this; // Just for clarity. + LLImageDataLock lock(this); + llassert( (4 == src->getComponents()) && (3 == dst->getComponents()) ); S32 temp_data_size = src->getWidth() * dst->getHeight() * src->getComponents(); @@ -1170,14 +1202,16 @@ void LLImageRaw::compositeScaled4onto3(LLImageRaw* src) // Src and dst are same size. Src has 4 components. Dst has 3 components. -void LLImageRaw::compositeUnscaled4onto3( LLImageRaw* src ) +void LLImageRaw::compositeUnscaled4onto3( const LLImageRaw* src ) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataLock lock(this); + llassert( (3 == src->getComponents()) || (4 == src->getComponents()) ); llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); - U8* src_data = src->getData(); + const U8* src_data = src->getData(); U8* dst_data = dst->getData(); S32 pixels = getWidth() * getHeight(); while( pixels-- ) @@ -1207,10 +1241,13 @@ void LLImageRaw::compositeUnscaled4onto3( LLImageRaw* src ) } -void LLImageRaw::copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill) +void LLImageRaw::copyUnscaledAlphaMask( const LLImageRaw* src, const LLColor4U& fill) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataSharedLock lockIn(src); + LLImageDataLock lockOut(this); + if (!validateSrcAndDst("LLImageRaw::copyUnscaledAlphaMask", src, dst)) { return; @@ -1221,7 +1258,7 @@ void LLImageRaw::copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill) llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); S32 pixels = getWidth() * getHeight(); - U8* src_data = src->getData(); + const U8* src_data = src->getData(); U8* dst_data = dst->getData(); for ( S32 i = 0; i < pixels; i++ ) { @@ -1238,6 +1275,8 @@ void LLImageRaw::copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill) // Fill the buffer with a constant color void LLImageRaw::fill( const LLColor4U& color ) { + LLImageDataLock lock(this); + if (isBufferInvalid()) { LL_WARNS() << "Invalid image buffer" << LL_ENDL; @@ -1275,16 +1314,21 @@ LLPointer LLImageRaw::duplicate() return this; //nobody else refences to this image, no need to duplicate. } + LLImageDataSharedLock lock(this); + //make a duplicate LLPointer dup = new LLImageRaw(getData(), getWidth(), getHeight(), getComponents()); return dup; } // Src and dst can be any size. Src and dst can each have 3 or 4 components. -void LLImageRaw::copy(LLImageRaw* src) +void LLImageRaw::copy(const LLImageRaw* src) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataSharedLock lockIn(src); + LLImageDataLock lockOut(this); + if (!validateSrcAndDst("LLImageRaw::copy", src, dst)) { return; @@ -1330,10 +1374,12 @@ void LLImageRaw::copy(LLImageRaw* src) } // Src and dst are same size. Src and dst have same number of components. -void LLImageRaw::copyUnscaled(LLImageRaw* src) +void LLImageRaw::copyUnscaled(const LLImageRaw* src) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataLock lock(this); + llassert( (1 == src->getComponents()) || (3 == src->getComponents()) || (4 == src->getComponents()) ); llassert( src->getComponents() == dst->getComponents() ); llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); @@ -1343,7 +1389,7 @@ void LLImageRaw::copyUnscaled(LLImageRaw* src) // Src and dst can be any size. Src has 3 components. Dst has 4 components. -void LLImageRaw::copyScaled3onto4(LLImageRaw* src) +void LLImageRaw::copyScaled3onto4(const LLImageRaw* src) { llassert( (3 == src->getComponents()) && (4 == getComponents()) ); @@ -1355,7 +1401,7 @@ void LLImageRaw::copyScaled3onto4(LLImageRaw* src) // Src and dst can be any size. Src has 4 components. Dst has 3 components. -void LLImageRaw::copyScaled4onto3(LLImageRaw* src) +void LLImageRaw::copyScaled4onto3(const LLImageRaw* src) { llassert( (4 == src->getComponents()) && (3 == getComponents()) ); @@ -1367,15 +1413,17 @@ void LLImageRaw::copyScaled4onto3(LLImageRaw* src) // Src and dst are same size. Src has 4 components. Dst has 3 components. -void LLImageRaw::copyUnscaled4onto3( LLImageRaw* src ) +void LLImageRaw::copyUnscaled4onto3( const LLImageRaw* src ) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataLock lock(this); + llassert( (3 == dst->getComponents()) && (4 == src->getComponents()) ); llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); S32 pixels = getWidth() * getHeight(); - U8* src_data = src->getData(); + const U8* src_data = src->getData(); U8* dst_data = dst->getData(); for( S32 i=0; igetComponents() ); llassert( 4 == dst->getComponents() ); llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); S32 pixels = getWidth() * getHeight(); - U8* src_data = src->getData(); + const U8* src_data = src->getData(); U8* dst_data = dst->getData(); for( S32 i=0; i LLImageRaw::scaled(S32 new_width, S32 new_height) { LLPointer result; + LLImageDataLock lock(this); + S32 components = getComponents(); if (components != 1 && components != 3 && components != 4) { @@ -1588,7 +1646,7 @@ LLPointer LLImageRaw::scaled(S32 new_width, S32 new_height) return result; } -void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ) +void LLImageRaw::copyLineScaled( const U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ) { const S32 components = getComponents(); llassert( components >= 1 && components <= 4 ); @@ -1615,7 +1673,7 @@ void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixe S32 t0 = x * out_pixel_step * components; S32 t1 = index0 * in_pixel_step * components; U8* outp = out + t0; - U8* inp = in + t1; + const U8* inp = in + t1; for (S32 i = 0; i < components; ++i) { *outp = *inp; @@ -1703,7 +1761,7 @@ void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixe } } -void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ) +void LLImageRaw::compositeRowScaled4onto3( const U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ) { llassert( getComponents() == 3 ); @@ -1799,8 +1857,12 @@ void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S3 } } -bool LLImageRaw::validateSrcAndDst(std::string func, LLImageRaw* src, LLImageRaw* dst) +// static +bool LLImageRaw::validateSrcAndDst(std::string func, const LLImageRaw* src, const LLImageRaw* dst) { + LLImageDataSharedLock lockIn(src); + LLImageDataLock lockOut(dst); + if (!src || !dst || src->isBufferInvalid() || dst->isBufferInvalid()) { LL_WARNS() << func << ": Source: "; @@ -2113,6 +2175,8 @@ bool LLImageFormatted::decodeChannels(LLImageRaw* raw_image,F32 decode_time, S3 // virtual U8* LLImageFormatted::allocateData(S32 size) { + LLImageDataLock lock(this); + U8* res = LLImageBase::allocateData(size); // calls deleteData() sGlobalFormattedMemory += getDataSize(); return res; @@ -2121,6 +2185,8 @@ U8* LLImageFormatted::allocateData(S32 size) // virtual U8* LLImageFormatted::reallocateData(S32 size) { + LLImageDataLock lock(this); + sGlobalFormattedMemory -= getDataSize(); U8* res = LLImageBase::reallocateData(size); sGlobalFormattedMemory += getDataSize(); @@ -2130,6 +2196,8 @@ U8* LLImageFormatted::reallocateData(S32 size) // virtual void LLImageFormatted::deleteData() { + LLImageDataLock lock(this); + if (mDecoding) { LL_ERRS() << "LLImageFormatted::deleteData() is called during decoding" << LL_ENDL; @@ -2159,6 +2227,8 @@ void LLImageFormatted::sanityCheck() bool LLImageFormatted::copyData(U8 *data, S32 size) { + LLImageDataLock lock(this); + if ( data && ((data != getData()) || (size != getDataSize())) ) { deleteData(); @@ -2171,6 +2241,8 @@ bool LLImageFormatted::copyData(U8 *data, S32 size) // LLImageFormatted becomes the owner of data void LLImageFormatted::setData(U8 *data, S32 size) { + LLImageDataLock lock(this); + if (data && data != getData()) { deleteData(); @@ -2184,6 +2256,8 @@ void LLImageFormatted::appendData(U8 *data, S32 size) { if (data) { + LLImageDataLock lock(this); + if (!getData()) { setData(data, size); @@ -2225,6 +2299,9 @@ bool LLImageFormatted::load(const std::string &filename, int load_size) { load_size = file_size; } + + LLImageDataLock lock(this); + bool res; U8 *data = allocateData(load_size); if (data) @@ -2262,8 +2339,10 @@ bool LLImageFormatted::save(const std::string &filename) setLastError("Unable to open file for writing", filename); return false; } - - outfile.write(getData(), getDataSize()); + + LLImageDataSharedLock lock(this); + + outfile.write(getData(), getDataSize()); outfile.close() ; return true; } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 8f9e1b3c54..cc6a58f417 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -116,7 +116,11 @@ class LLImageBase { protected: virtual ~LLImageBase(); - + + virtual void deleteData(); + virtual U8* allocateData(S32 size = -1); + virtual U8* reallocateData(S32 size = -1); + public: LLImageBase(); @@ -126,10 +130,6 @@ public: TYPE_AVATAR_BAKE = 1, }; - virtual void deleteData(); - virtual U8* allocateData(S32 size = -1); - virtual U8* reallocateData(S32 size = -1); - virtual void dump(); virtual void sanityCheck(); @@ -171,10 +171,27 @@ private: S8 mComponents; - bool mBadBufferAllocation ; - bool mAllowOverSize ; + bool mBadBufferAllocation; + bool mAllowOverSize; + +private: + mutable LLSharedMutex mDataMutex; + +public: + template + class DataLock : LLSharedMutexLockTemplate + { + public: + DataLock(const LLImageBase* image) + : LLSharedMutexLockTemplate(image ? &image->mDataMutex : nullptr) + { + } + }; }; +using LLImageDataLock = LLImageBase::DataLock; +using LLImageDataSharedLock = LLImageBase::DataLock; + // Raw representation of an image (used for textures, and other uncompressed formats class LLImageRaw : public LLImageBase { @@ -231,51 +248,51 @@ public: LLPointer duplicate(); // Src and dst can be any size. Src and dst can each have 3 or 4 components. - void copy( LLImageRaw* src ); + void copy( const LLImageRaw* src ); // Src and dst are same size. Src and dst have same number of components. - void copyUnscaled( LLImageRaw* src ); + void copyUnscaled( const LLImageRaw* src ); // Src and dst are same size. Src has 4 components. Dst has 3 components. - void copyUnscaled4onto3( LLImageRaw* src ); + void copyUnscaled4onto3( const LLImageRaw* src ); // Src and dst are same size. Src has 3 components. Dst has 4 components. - void copyUnscaled3onto4( LLImageRaw* src ); + void copyUnscaled3onto4( const LLImageRaw* src ); // Src and dst are same size. Src has 1 component. Dst has 4 components. // Alpha component is set to source alpha mask component. // RGB components are set to fill color. - void copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill); + void copyUnscaledAlphaMask( const LLImageRaw* src, const LLColor4U& fill); // Src and dst can be any size. Src and dst have same number of components. - void copyScaled( LLImageRaw* src ); - - // Src and dst can be any size. Src has 3 components. Dst has 4 components. - void copyScaled3onto4( LLImageRaw* src ); - - // Src and dst can be any size. Src has 4 components. Dst has 3 components. - void copyScaled4onto3( LLImageRaw* src ); + void copyScaled( const LLImageRaw* src ); // Composite operations // Src and dst can be any size. Src and dst can each have 3 or 4 components. - void composite( LLImageRaw* src ); - - // Src and dst can be any size. Src has 4 components. Dst has 3 components. - void compositeScaled4onto3( LLImageRaw* src ); - - // Src and dst are same size. Src has 4 components. Dst has 3 components. - void compositeUnscaled4onto3( LLImageRaw* src ); + void composite( const LLImageRaw* src ); protected: + // Src and dst can be any size. Src has 4 components. Dst has 3 components. + void compositeScaled4onto3( const LLImageRaw* src ); + + // Src and dst are same size. Src has 4 components. Dst has 3 components. + void compositeUnscaled4onto3( const LLImageRaw* src ); + + // Src and dst can be any size. Src has 3 components. Dst has 4 components. + void copyScaled3onto4( const LLImageRaw* src ); + + // Src and dst can be any size. Src has 4 components. Dst has 3 components. + void copyScaled4onto3( const LLImageRaw* src ); + // Create an image from a local file (generally used in tools) //bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false); - void copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ); - void compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ); + void copyLineScaled( const U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ); + void compositeRowScaled4onto3( const U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ); - U8 fastFractionalMult(U8 a,U8 b); + static U8 fastFractionalMult(U8 a, U8 b); void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ; @@ -283,7 +300,7 @@ public: static S32 sRawImageCount; private: - bool validateSrcAndDst(std::string func, LLImageRaw* src, LLImageRaw* dst); + static bool validateSrcAndDst(std::string func, const LLImageRaw* src, const LLImageRaw* dst); }; // Compressed representation of image. @@ -356,7 +373,7 @@ protected: S8 mDecoded; // unused, but changing LLImage layout requires recompiling static Mac/Linux libs. 2009-01-30 JC S8 mDiscardLevel; // Current resolution level worked on. 0 = full res, 1 = half res, 2 = quarter res, etc... S8 mLevels; // Number of resolution levels in that image. Min is 1. 0 means unknown. - + public: static S32 sGlobalFormattedMemory; }; diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp index 90b7272efa..d26d160537 100644 --- a/indra/llimage/llimagebmp.cpp +++ b/indra/llimage/llimagebmp.cpp @@ -96,6 +96,8 @@ bool LLImageBMP::updateData() { resetLastError(); + LLImageDataLock lock(this); + // Check to make sure that this instance has been initialized with data U8* mdata = getData(); if (!mdata || (0 == getDataSize())) @@ -336,8 +338,11 @@ bool LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time) resetLastError(); + LLImageDataLock lockIn(this); + LLImageDataLock lockOut(raw_image); + // Check to make sure that this instance has been initialized with data - U8* mdata = getData(); + const U8* mdata = getData(); if (!mdata || (0 == getDataSize())) { setLastError("llimagebmp trying to decode an image with no data!"); @@ -350,7 +355,7 @@ bool LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time) return false; } - U8* src = mdata + mBitmapOffset; + const U8* src = mdata + mBitmapOffset; U8* dst = raw_image->getData(); bool success = false; @@ -397,7 +402,7 @@ U32 LLImageBMP::countTrailingZeros( U32 m ) } -bool LLImageBMP::decodeColorMask16( U8* dst, U8* src ) +bool LLImageBMP::decodeColorMask16( U8* dst, const U8* src ) { llassert( 16 == mBitsPerPixel ); @@ -433,7 +438,7 @@ bool LLImageBMP::decodeColorMask16( U8* dst, U8* src ) return true; } -bool LLImageBMP::decodeColorMask32( U8* dst, U8* src ) +bool LLImageBMP::decodeColorMask32( U8* dst, const U8* src ) { // Note: alpha is not supported @@ -477,7 +482,7 @@ bool LLImageBMP::decodeColorMask32( U8* dst, U8* src ) } -bool LLImageBMP::decodeColorTable8( U8* dst, U8* src ) +bool LLImageBMP::decodeColorTable8( U8* dst, const U8* src ) { llassert( (8 == mBitsPerPixel) && (mColorPaletteColors >= 256) ); @@ -507,7 +512,7 @@ bool LLImageBMP::decodeColorTable8( U8* dst, U8* src ) } -bool LLImageBMP::decodeTruecolor24( U8* dst, U8* src ) +bool LLImageBMP::decodeTruecolor24( U8* dst, const U8* src ) { llassert( 24 == mBitsPerPixel ); llassert( 3 == getComponents() ); @@ -541,6 +546,9 @@ bool LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time) resetLastError(); + LLImageDataSharedLock lockIn(raw_image); + LLImageDataLock lockOut(this); + S32 src_components = raw_image->getComponents(); S32 dst_components = ( src_components < 3 ) ? 1 : 3; diff --git a/indra/llimage/llimagebmp.h b/indra/llimage/llimagebmp.h index 6a5fa4697d..295f96e541 100644 --- a/indra/llimage/llimagebmp.h +++ b/indra/llimage/llimagebmp.h @@ -45,10 +45,10 @@ public: /*virtual*/ bool encode(const LLImageRaw* raw_image, F32 encode_time); protected: - bool decodeColorTable8( U8* dst, U8* src ); - bool decodeColorMask16( U8* dst, U8* src ); - bool decodeTruecolor24( U8* dst, U8* src ); - bool decodeColorMask32( U8* dst, U8* src ); + bool decodeColorTable8( U8* dst, const U8* src ); + bool decodeColorMask16( U8* dst, const U8* src ); + bool decodeTruecolor24( U8* dst, const U8* src ); + bool decodeColorMask32( U8* dst, const U8* src ); U32 countTrailingZeros( U32 m ); diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 36317a5ba8..f4bb3bb120 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -176,6 +176,8 @@ bool LLImageDXT::updateData() { resetLastError(); + LLImageDataLock lock(this); + U8* data = getData(); S32 data_size = getDataSize(); @@ -268,7 +270,10 @@ bool LLImageDXT::decode(LLImageRaw* raw_image, F32 time) LL_WARNS() << "Attempt to decode compressed LLImageDXT to Raw (unsupported)" << LL_ENDL; return false; } - + + LLImageDataSharedLock lockIn(this); + LLImageDataLock lockOut(raw_image); + S32 width = getWidth(), height = getHeight(); S32 ncomponents = getComponents(); U8* data = NULL; @@ -309,6 +314,9 @@ bool LLImageDXT::getMipData(LLPointer& raw, S32 discard) { LL_ERRS() << "Request for invalid discard level" << LL_ENDL; } + + LLImageDataSharedLock lock(this); + U8* data = getData() + getMipOffset(discard); S32 width = 0; S32 height = 0; @@ -339,6 +347,8 @@ bool LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_ return 0; } + LLImageDataLock lock(this); + S32 width = raw_image->getWidth(); S32 height = raw_image->getHeight(); @@ -430,6 +440,9 @@ bool LLImageDXT::convertToDXR() return false; } mFileFormat = newformat; + + LLImageDataLock lock(this); + S32 width = getWidth(), height = getHeight(); S32 nmips = calcNumMips(width,height); S32 total_bytes = getDataSize(); diff --git a/indra/llimage/llimagefilter.cpp b/indra/llimage/llimagefilter.cpp index 41adc7be9a..61c2e1d742 100644 --- a/indra/llimage/llimagefilter.cpp +++ b/indra/llimage/llimagefilter.cpp @@ -87,7 +87,9 @@ LLImageFilter::~LLImageFilter() void LLImageFilter::executeFilter(LLPointer raw_image) { mImage = raw_image; - + + LLImageDataLock lock(mImage); + //std::cout << "Filter : size = " << mFilterData.size() << std::endl; for (S32 i = 0; i < mFilterData.size(); ++i) { diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index a4957466d4..a06c461107 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -107,6 +107,8 @@ bool LLImageJ2C::updateData() bool res = true; resetLastError(); + LLImageDataLock lock(this); + // Check to make sure that this instance has been initialized with data if (!getData() || (getDataSize() < 16)) { @@ -158,22 +160,26 @@ bool LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir LLTimer elapsed; resetLastError(); - mDecoding = true; bool res; - // Check to make sure that this instance has been initialized with data - if (!getData() || (getDataSize() < 16)) { - setLastError("LLImageJ2C uninitialized"); - res = true; // done + LLImageDataLock lock(this); + + mDecoding = true; + // Check to make sure that this instance has been initialized with data + if (!getData() || (getDataSize() < 16)) + { + setLastError("LLImageJ2C uninitialized"); + res = true; // done + } + else + { + // Update the raw discard level + updateRawDiscardLevel(); + res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); + } } - else - { - // Update the raw discard level - updateRawDiscardLevel(); - res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); - } - + if (res) { if (!mDecoding) @@ -414,9 +420,10 @@ bool LLImageJ2C::loadAndValidate(const std::string &filename) bool LLImageJ2C::validate(U8 *data, U32 file_size) { - resetLastError(); - + + LLImageDataLock lock(this); + setData(data, file_size); bool res = updateData(); diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp index 32a5472ec8..a35171601a 100644 --- a/indra/llimage/llimagejpeg.cpp +++ b/indra/llimage/llimagejpeg.cpp @@ -50,6 +50,8 @@ bool LLImageJPEG::updateData() { resetLastError(); + LLImageDataLock lock(this); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -188,7 +190,10 @@ bool LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) llassert_always(raw_image); resetLastError(); - + + LLImageDataLock lockIn(this); + LLImageDataLock lockOut(raw_image); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -408,6 +413,8 @@ void LLImageJPEG::encodeTermDestination( j_compress_ptr cinfo ) { LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; + LLImageDataLock lock(self); + S32 file_bytes = (S32)(self->mOutputBufferSize - cinfo->dest->free_in_buffer); self->allocateData(file_bytes); @@ -484,6 +491,9 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time ) resetLastError(); + LLImageDataSharedLock lockIn(raw_image); + LLImageDataLock lockOut(this); + switch( raw_image->getComponents() ) { case 1: diff --git a/indra/llimage/llimagejpeg.h b/indra/llimage/llimagejpeg.h index 7a849a8421..d674b40b8f 100644 --- a/indra/llimage/llimagejpeg.h +++ b/indra/llimage/llimagejpeg.h @@ -73,8 +73,6 @@ public: static void errorEmitMessage(j_common_ptr cinfo, int msg_level); static void errorOutputMessage(j_common_ptr cinfo); - static bool decompress(LLImageJPEG* imagep); - protected: U8* mOutputBuffer; // temp buffer used during encoding S32 mOutputBufferSize; // bytes in mOuputBuffer diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp index c4b98d8260..5d956bfb4e 100644 --- a/indra/llimage/llimagepng.cpp +++ b/indra/llimage/llimagepng.cpp @@ -51,6 +51,8 @@ bool LLImagePNG::updateData() { resetLastError(); + LLImageDataLock lock(this); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -87,6 +89,9 @@ bool LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time) resetLastError(); + LLImageDataSharedLock lockIn(this); + LLImageDataLock lockOut(raw_image); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -119,6 +124,9 @@ bool LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time) resetLastError(); + LLImageDataSharedLock lockIn(raw_image); + LLImageDataLock lockOut(this); + // Image logical size setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents()); diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index 88bdae9b80..290c0da4bf 100644 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -108,6 +108,8 @@ bool LLImageTGA::updateData() { resetLastError(); + LLImageDataLock lock(this); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -326,7 +328,10 @@ bool LLImageTGA::updateData() bool LLImageTGA::decode(LLImageRaw* raw_image, F32 decode_time) { llassert_always(raw_image); - + + LLImageDataSharedLock lockIn(this); + LLImageDataLock lockOut(raw_image); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -642,7 +647,10 @@ bool LLImageTGA::decodeColorMap( LLImageRaw* raw_image, bool rle, bool flipped ) bool LLImageTGA::encode(const LLImageRaw* raw_image, F32 encode_time) { llassert_always(raw_image); - + + LLImageDataSharedLock lockIn(raw_image); + LLImageDataLock lockOut(this); + deleteData(); setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents()); @@ -1061,6 +1069,9 @@ bool LLImageTGA::decodeAndProcess( LLImageRaw* raw_image, F32 domain, F32 weight // --+---Input-------------------------------- // | + LLImageDataSharedLock lockIn(this); + LLImageDataLock lockOut(raw_image); + if (!getData() || (0 == getDataSize())) { setLastError("LLImageTGA trying to decode an image with no data!"); diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index c1ee052997..44749343e1 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -149,9 +149,18 @@ ImageRequest::~ImageRequest() bool ImageRequest::processRequest() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + + if (mFormattedImage.isNull()) + return true; + const F32 decode_time_slice = 0.f; //disable time slicing bool done = true; - if (!mDecodedRaw && mFormattedImage.notNull()) + + LLImageDataLock lockFormatted(mFormattedImage); + LLImageDataLock lockDecodedRaw(mDecodedImageRaw); + LLImageDataLock lockDecodedAux(mDecodedImageAux); + + if (!mDecodedRaw) { // Decode primary channels if (mDecodedImageRaw.isNull()) @@ -177,7 +186,7 @@ bool ImageRequest::processRequest() // some decoders are removing data when task is complete and there were errors mDecodedRaw = done && mDecodedImageRaw->getData(); } - if (done && mNeedsAux && !mDecodedAux && mFormattedImage.notNull()) + if (done && mNeedsAux && !mDecodedAux) { // Decode aux channel if (!mDecodedImageAux) diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index cad7c00042..27e23b577b 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -173,6 +173,8 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf // data space if (rawImage != NULL) { + LLImageDataLock lock(rawImage); + if (!rawImage->resize(static_cast(mWidth), static_cast(mHeight), mChannels)) { diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index 6c06c6de38..482d2a2c8a 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -489,6 +489,9 @@ public: bool encode(const LLImageRaw& rawImageIn, LLImageJ2C &compressedImageOut) { + LLImageDataSharedLock lockIn(&rawImageIn); + LLImageDataLock lockOut(&compressedImageOut); + setImage(rawImageIn); encoder = opj_create_compress(OPJ_CODEC_J2K); @@ -733,6 +736,9 @@ bool LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int block bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) { + LLImageDataLock lockIn(&base); + LLImageDataLock lockOut(&raw_image); + JPEG2KDecode decoder(0); U32 image_channels = 0; @@ -820,6 +826,8 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con bool LLImageJ2COJ::getMetadata(LLImageJ2C &base) { + LLImageDataLock lock(&base); + JPEG2KDecode decode(0); S32 width = 0; diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index d96cd105dd..8b34592535 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -277,6 +277,8 @@ void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision); // as well, when that still existed, with keep_codestream true and MODE_FAST. void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECodeStreamMode mode) { + LLImageDataLock lock(&base); + S32 data_size = base.getDataSize(); S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size); @@ -512,6 +514,10 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + + LLImageDataLock lockIn(&base); + LLImageDataLock lockOut(&raw_image); + ECodeStreamMode mode = MODE_FAST; bool limit_time = decode_time > 0.0f; @@ -529,7 +535,7 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco // These can probably be grabbed from what's saved in the class. kdu_dims dims; - mCodeStreamp->get_dims(0,dims); + mCodeStreamp->get_dims(0, dims); // Now we are ready to walk through the tiles processing them one-by-one. kdu_byte *buffer = raw_image.getData(); @@ -579,7 +585,7 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco mCodeStreamp.get())); } // Do the actual processing - F32 remaining_time = limit_time ? static_cast(decode_time - decode_timer.getElapsedTimeF32()) : 0.0f; + F32 remaining_time = limit_time ? decode_time - decode_timer.getElapsedTimeF32().value() : 0.0f; // This is where we do the actual decode. If we run out of time, return false. if (mDecodeState->processTileDecode(remaining_time, limit_time)) { diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 254288a86e..26bd925f03 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -111,6 +111,9 @@ void LLCubeMap::initRawData(const std::vector >& rawimages // Yes, I know that this is inefficient! - djs 08/08/02 for (int i = 0; i < 6; i++) { + LLImageDataSharedLock lockIn(rawimages[i]); + LLImageDataLock lockOut(mRawImages[i]); + const U8 *sd = rawimages[i]->getData(); U8 *td = mRawImages[i]->getData(); diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index e964d1586f..11a379d70f 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -669,6 +669,7 @@ U8 LLFontFreetype::getStyle() const void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const { LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); + LLImageDataLock lock(image_raw); llassert(!mIsFallback); llassert(image_raw && (image_raw->getComponents() == 2)); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index c6fd824c4e..bbedcf360c 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1887,6 +1887,8 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre } //----------------------------------------------------------------------------------------------- + LLImageDataLock lock(imageraw); + if (is_compressed) { LLGLint glbytes; diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index a0ce0ef6cf..77a196380b 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -849,11 +849,14 @@ void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTextu void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nrm_image) { + LLImageDataSharedLock lockIn(src); + LLImageDataLock lockOut(nrm_image); + U8* nrm_data = nrm_image->getData(); S32 resX = src->getWidth(); S32 resY = src->getHeight(); - U8* src_data = src->getData(); + const U8* src_data = src->getData(); S32 src_cmp = src->getComponents(); @@ -911,6 +914,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LLImageDataSharedLock lock(src); bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries ); bump_image_map_t::iterator iter = entries_list.find(source_asset_id); @@ -933,7 +937,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI U8* dst_data = dst_image->getData(); S32 dst_data_size = dst_image->getDataSize(); - U8* src_data = src->getData(); + const U8* src_data = src->getData(); S32 src_data_size = src->getDataSize(); S32 src_components = src->getComponents(); diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 5b8ca6c49c..9cf9f45bfb 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -448,6 +448,8 @@ void saveChart(const std::string& label, const char* suffix, LLImageRaw* scratch // disable use of glReadPixels which messes up nVidia nSight graphics debugging if (!LLRender::sNsightDebugSupport) { + LLImageDataSharedLock lock(scratch); + //read result back into raw image glReadPixels(0, 0, 1024, 512, GL_RGB, GL_UNSIGNED_BYTE, scratch->getData()); diff --git a/indra/newview/llfloater360capture.cpp b/indra/newview/llfloater360capture.cpp index 2c638fa959..a0890b7f9d 100644 --- a/indra/newview/llfloater360capture.cpp +++ b/indra/newview/llfloater360capture.cpp @@ -360,6 +360,8 @@ void LLFloater360Capture::encodeAndSave(LLPointer raw_image, const s int jpeg_encode_quality = gSavedSettings.getU32("360CaptureJPEGEncodeQuality"); LLPointer jpeg_image = new LLImageJPEG(jpeg_encode_quality); + LLImageDataSharedLock lock(raw_image); + // Actually encode the JPEG image. This is where a lot of time // is spent now that the snapshot capture process has been // optimized. The encode_time parameter doesn't appear to be @@ -410,6 +412,8 @@ void LLFloater360Capture::suspendForAFrame() // Probably not needed anymore but saving here just in case. void LLFloater360Capture::mockSnapShot(LLImageRaw* raw) { + LLImageDataLock lock(raw); + unsigned int width = raw->getWidth(); unsigned int height = raw->getHeight(); unsigned int depth = raw->getComponents(); diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index 9813156bf2..6996224dcb 100644 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -190,6 +190,8 @@ void LLFloaterAuction::onClickSnapshot(void* data) if (success) { + LLImageDataLock lock(raw); + self->mTransactionID.generate(); self->mImageID = self->mTransactionID.makeAssetID(gAgent.getSecureSessionID()); diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp index ba91277c79..af96fdbcfd 100644 --- a/indra/newview/llfloatercolorpicker.cpp +++ b/indra/newview/llfloatercolorpicker.cpp @@ -135,6 +135,8 @@ void LLFloaterColorPicker::createUI () // create RGB type area (not really RGB but it's got R,G & B in it.,.. LLPointer raw = new LLImageRaw ( mRGBViewerImageWidth, mRGBViewerImageHeight, mComponents ); + LLImageDataLock lock(raw); + U8* bits = raw->getData(); S32 linesize = mRGBViewerImageWidth * mComponents; for ( S32 y = 0; y < mRGBViewerImageHeight; ++y ) diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index ba0f97e2e1..5e7978e224 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -789,6 +789,7 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance) if (imagep) { + LLImageDataSharedLock lock(imagep); mVolume->sculpt(imagep->getWidth(), imagep->getHeight(), imagep->getComponents(), imagep->getData(), 0, false); } diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index c8ac73b838..e966514955 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -70,7 +70,7 @@ void modify_outfit(BOOL append, const LLUUID& cat_id, LLInventoryModel* model) if (items.size() > max_items()) { LLSD args; - args["AMOUNT"] = llformat("%d", static_cast(max_items)); + args["AMOUNT"] = llformat("%u", max_items()); LLNotificationsUtil::add("TooManyWearables", args); return; } diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 5e78e15c72..415543eb37 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -3424,6 +3424,8 @@ void LLMaterialEditor::inventoryChanged(LLViewerObject* object, void LLMaterialEditor::saveTexture(LLImageJ2C* img, const std::string& name, const LLUUID& asset_id, upload_callback_f cb) { + LLImageDataSharedLock lock(img); + if (asset_id.isNull() || img == nullptr || img->getDataSize() == 0) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 01d6469010..2622c23314 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2360,17 +2360,19 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) std::stringstream texture_str; if (texture != NULL && include_textures && mUploadTextures) { - if(texture->hasSavedRawImage()) - { + if (texture->hasSavedRawImage()) + { + LLImageDataLock lock(texture->getSavedRawImage()); + LLPointer upload_file = LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage()); if (!upload_file.isNull() && upload_file->getDataSize()) { - texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); + texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); + } } } - } if (texture != NULL && mUploadTextures && @@ -2514,17 +2516,19 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) std::stringstream texture_str; if (texture != NULL && include_textures && mUploadTextures) { - if(texture->hasSavedRawImage()) - { + if (texture->hasSavedRawImage()) + { + LLImageDataLock lock(texture->getSavedRawImage()); + LLPointer upload_file = LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage()); if (!upload_file.isNull() && upload_file->getDataSize()) { - texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); + texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); + } } } - } if (texture != NULL && mUploadTextures && diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 0ba3c3d691..e7f9d0e5df 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -345,6 +345,7 @@ void LLNetMap::draw() mObjectImageCenterGlobal = viewPosToGlobal(llfloor(new_center.mV[VX]), llfloor(new_center.mV[VY])); // Create the base texture. + LLImageDataLock lock(mObjectRawImagep); U8 *default_texture = mObjectRawImagep->getData(); memset( default_texture, 0, mObjectImagep->getWidth() * mObjectImagep->getHeight() * mObjectImagep->getComponents() ); @@ -915,6 +916,7 @@ void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color, return; } + LLImageDataLock lock(mObjectRawImagep); U8 *datap = mObjectRawImagep->getData(); S32 neg_radius = diameter / 2; diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index b7a1832b17..bb7c73b59f 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -766,6 +766,8 @@ void LLSnapshotLivePreview::prepareFreezeFrame() // Get the decoded version of the formatted image getEncodedImage(); + LLImageDataSharedLock lock(mPreviewImageEncoded); + // We need to scale that a bit for display... LLPointer scaled = new LLImageRaw( mPreviewImageEncoded->getData(), @@ -825,13 +827,15 @@ LLPointer LLSnapshotLivePreview::getEncodedImage() { if (!mPreviewImageEncoded) { + LLImageDataSharedLock lock(mPreviewImage); + mPreviewImageEncoded = new LLImageRaw; - + mPreviewImageEncoded->resize( mPreviewImage->getWidth(), mPreviewImage->getHeight(), mPreviewImage->getComponents()); - + if (getSnapshotType() == LLSnapshotModel::SNAPSHOT_TEXTURE) { // We don't store the intermediate formatted image in mFormattedImage in the J2C case @@ -978,6 +982,8 @@ void LLSnapshotLivePreview::getSize(S32& w, S32& h) const void LLSnapshotLivePreview::saveTexture(BOOL outfit_snapshot, std::string name) { + LLImageDataSharedLock lock(mPreviewImage); + LL_DEBUGS("Snapshot") << "saving texture: " << mPreviewImage->getWidth() << "x" << mPreviewImage->getHeight() << LL_ENDL; // gen a new uuid for this asset LLTransactionID tid; diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index a14d4f7a30..dfaeeaab62 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -96,7 +96,7 @@ private: public: LLTextureCacheWorker(LLTextureCache* cache, const LLUUID& id, - U8* data, S32 datasize, S32 offset, + const U8* data, S32 datasize, S32 offset, S32 imagesize, // for writes LLTextureCache::Responder* responder) : LLWorkerClass(cache, "LLTextureCacheWorker"), @@ -145,7 +145,7 @@ protected: LLUUID mID; U8* mReadData; - U8* mWriteData; + const U8* mWriteData; S32 mDataSize; S32 mOffset; S32 mImageSize; @@ -239,7 +239,7 @@ class LLTextureCacheRemoteWorker : public LLTextureCacheWorker { public: LLTextureCacheRemoteWorker(LLTextureCache* cache, const LLUUID& id, - U8* data, S32 datasize, S32 offset, + const U8* data, S32 datasize, S32 offset, S32 imagesize, // for writes LLPointer raw, S32 discardlevel, LLTextureCache::Responder* responder) @@ -1961,7 +1961,7 @@ bool LLTextureCache::readComplete(handle_t handle, bool abort) } LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, - U8* data, S32 datasize, S32 imagesize, + const U8* data, S32 datasize, S32 imagesize, LLPointer rawimage, S32 discardlevel, WriteResponder* responder) { @@ -2047,6 +2047,9 @@ LLPointer LLTextureCache::readFromFastCache(const LLUUID& id, S32& d bool LLTextureCache::writeToFastCache(LLUUID image_id, S32 id, LLPointer raw, S32 discardlevel) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + + LLImageDataSharedLock lock(raw); + //rescale image if needed if (raw.isNull() || raw->isBufferInvalid() || !raw->getData()) { diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index 43e91b3e4c..cba45393f9 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -125,7 +125,7 @@ public: handle_t readFromCache(const LLUUID& id, S32 offset, S32 size, ReadResponder* responder); bool readComplete(handle_t handle, bool abort); - handle_t writeToCache(const LLUUID& id, U8* data, S32 datasize, S32 imagesize, LLPointer rawimage, S32 discardlevel, + handle_t writeToCache(const LLUUID& id, const U8* data, S32 datasize, S32 imagesize, LLPointer rawimage, S32 discardlevel, WriteResponder* responder); LLPointer readFromFastCache(const LLUUID& id, S32& discardlevel); bool writeComplete(handle_t handle, bool abort = false); diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 38c9b3717d..4ecabf666b 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1699,7 +1699,9 @@ bool LLTextureFetchWorker::doWork(S32 param) mFormattedImage = new LLImageJ2C; // default } } - + + LLImageDataLock lock(mFormattedImage); + if (mHaveAllData) //the image file is fully loaded. { mFileSize = total_size; @@ -1857,6 +1859,9 @@ bool LLTextureFetchWorker::doWork(S32 param) //return false; return doWork(param); } + + LLImageDataSharedLock lock(mFormattedImage); + S32 datasize = mFormattedImage->getDataSize(); if(mFileSize < datasize)//This could happen when http fetching and sim fetching mixed. { diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp index 999be07dba..cee18489f0 100644 --- a/indra/newview/lltinygltfhelper.cpp +++ b/indra/newview/lltinygltfhelper.cpp @@ -31,7 +31,7 @@ #include "llviewertexture.h" #include "llviewertexturelist.h" -void strip_alpha_channel(LLPointer& img) +static void strip_alpha_channel(LLPointer& img) { if (img->getComponents() == 4) { @@ -45,13 +45,13 @@ void strip_alpha_channel(LLPointer& img) // PRECONDITIONS: // dst_img must be 3 component // src_img and dst_image must have the same dimensions -void copy_red_channel(LLPointer& src_img, LLPointer& dst_img) +static void copy_red_channel(const LLPointer& src_img, LLPointer& dst_img) { llassert(src_img->getWidth() == dst_img->getWidth() && src_img->getHeight() == dst_img->getHeight()); llassert(dst_img->getComponents() == 3); U32 pixel_count = dst_img->getWidth() * dst_img->getHeight(); - U8* src = src_img->getData(); + const U8* src = src_img->getData(); U8* dst = dst_img->getData(); S8 src_components = src_img->getComponents(); @@ -95,6 +95,8 @@ void LLTinyGLTFHelper::initFetchedTextures(tinygltf::Material& material, int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index; if (occlusion_idx != mr_idx) { + LLImageDataLock lockIn(occlusion_img); + LLImageDataLock lockOut(mr_img); //scale occlusion image to match resolution of mr image occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight()); @@ -104,6 +106,7 @@ void LLTinyGLTFHelper::initFetchedTextures(tinygltf::Material& material, } else if (occlusion_img) { + LLImageDataSharedLock lock(occlusion_img); //no mr but occlusion exists, make a white mr_img and copy occlusion red channel over mr_img = new LLImageRaw(occlusion_img->getWidth(), occlusion_img->getHeight(), 3); mr_img->clear(255, 255, 255); diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index a2b0b04092..dcb14eb383 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -654,6 +654,8 @@ LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLPointer(image->getCodec()); switch (codec) diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 785c84c38d..e1f372d396 100755 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -344,6 +344,8 @@ void LLViewerParcelOverlay::updateOverlayTexture() const LLColor4U for_sale = LLUIColorTable::instance().getColor("PropertyColorForSale").get(); const LLColor4U auction = LLUIColorTable::instance().getColor("PropertyColorAuction").get(); + LLImageDataLock lock(mImageRaw); + // Create the base texture. U8 *raw = mImageRaw->getData(); const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index ec6f2c848f..820a051782 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -285,6 +285,7 @@ LLPointer LLViewerTextureManager::getLocalTexture(const U32 wid LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(const LLImageRaw* raw, FTType type, bool usemipmaps) { + LLImageDataSharedLock lock(raw); LLViewerFetchedTexture* ret = new LLViewerFetchedTexture(raw, type, usemipmaps); gTextureList.addImage(ret, TEX_LIST_STANDARD); return ret; @@ -2905,6 +2906,8 @@ void LLViewerFetchedTexture::saveRawImage() return; } + LLImageDataSharedLock lock(mRawImage); + mSavedRawDiscardLevel = mRawDiscardLevel; if (mBoostLevel == LLGLTexture::BOOST_ICON) { diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index f898fb7142..7931b74b11 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1252,6 +1252,8 @@ bool LLViewerTextureList::createUploadFile(LLPointer raw_image, { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + LLImageDataSharedLock lock(raw_image); + // make a copy, since convertToUploadFile scales raw image LLPointer scale_image = new LLImageRaw( raw_image->getData(), @@ -1357,6 +1359,8 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename, LLPointer LLViewerTextureList::convertToUploadFile(LLPointer raw_image, const S32 max_image_dimentions, bool force_square, bool force_lossless) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + LLImageDataLock lock(raw_image); + if (force_square) { S32 biggest_side = llmax(raw_image->getWidth(), raw_image->getHeight()); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index ba2b6e1c7c..27ec8d9376 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -4890,6 +4890,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei { return FALSE; } + //check if there is enough memory for the snapshot image if(image_width * image_height > (1 << 22)) //if snapshot image is larger than 2K by 2K { @@ -5008,6 +5009,9 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei image_buffer_x = llfloor(snapshot_width * scale_factor) ; image_buffer_y = llfloor(snapshot_height * scale_factor) ; } + + LLImageDataLock lock(raw); + if ((image_buffer_x > 0) && (image_buffer_y > 0)) { raw->resize(image_buffer_x, image_buffer_y, 3); @@ -5266,6 +5270,8 @@ BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_ display(do_rebuild, zoom, subfield, for_snapshot); } + LLImageDataSharedLock lock(raw); + glReadPixels( 0, 0, image_width, diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index fee00eb6f4..8ab7cda28c 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -8894,7 +8894,7 @@ void LLVOAvatar::clearChat() } -void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index) +void LLVOAvatar::applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index) { if (index >= BAKED_NUM_INDICES) { @@ -9770,6 +9770,8 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture { if(aux_src && aux_src->getComponents() == 1) { + LLImageDataSharedLock lock(aux_src); + if (!aux_src->getData()) { LL_ERRS() << "No auxiliary source (morph mask) data for image id " << id << LL_ENDL; diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 48bfd5293a..759d02959c 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -590,7 +590,7 @@ public: // Morph masks //-------------------------------------------------------------------- public: - /*virtual*/ void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES); + /*virtual*/ void applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES); BOOL morphMaskNeedsUpdate(LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES); diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index 20621665fa..db197335f2 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -166,6 +166,7 @@ S32 LLSkyTex::getWhich(const BOOL curr) void LLSkyTex::initEmpty(const S32 tex) { + LLImageDataLock lock(mImageRaw[tex]); U8* data = mImageRaw[tex]->getData(); for (S32 i = 0; i < SKYTEX_RESOLUTION; ++i) { @@ -187,7 +188,8 @@ void LLSkyTex::initEmpty(const S32 tex) void LLSkyTex::create() { - U8* data = mImageRaw[sCurrent]->getData(); + LLImageDataSharedLock lock(mImageRaw[sCurrent]); + const U8* data = mImageRaw[sCurrent]->getData(); for (S32 i = 0; i < SKYTEX_RESOLUTION; ++i) { for (S32 j = 0; j < SKYTEX_RESOLUTION; ++j) diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h index 5941ab6e3b..509ad97786 100644 --- a/indra/newview/llvosky.h +++ b/indra/newview/llvosky.h @@ -101,6 +101,7 @@ protected: void setPixel(const LLColor4U &col, const S32 i, const S32 j) { + LLImageDataSharedLock lock(mImageRaw[sCurrent]); S32 offset = (i * SKYTEX_RESOLUTION + j) * SKYTEX_COMPONENTS; U32* pix = (U32*) &(mImageRaw[sCurrent]->getData()[offset]); *pix = col.asRGBA(); @@ -109,6 +110,7 @@ protected: LLColor4U getPixel(const S32 i, const S32 j) { LLColor4U col; + LLImageDataSharedLock lock(mImageRaw[sCurrent]); S32 offset = (i * SKYTEX_RESOLUTION + j) * SKYTEX_COMPONENTS; U32* pix = (U32*) &(mImageRaw[sCurrent]->getData()[offset]); col.fromRGBA( *pix ); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index ec2f490742..8846e30145 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1311,11 +1311,13 @@ void LLVOVolume::sculpt() } } else - { + { + LLImageDataSharedLock lock(raw_image); + sculpt_height = raw_image->getHeight(); sculpt_width = raw_image->getWidth(); sculpt_components = raw_image->getComponents(); - + sculpt_data = raw_image->getData(); if(LLViewerTextureManager::sTesterp) diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index f2d7e4585a..ade9bbd847 100644 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -239,10 +239,12 @@ LLCore::BufferArray::ptr_t LLWebProfile::buildPostData(const LLSD &data, LLPoint << "Content-Disposition: form-data; name=\"file\"; filename=\"snapshot.png\"\r\n" << "Content-Type: image/png\r\n\r\n"; + LLImageDataSharedLock lock(image); + // Insert the image data. //char *datap = (char *)(image->getData()); //bas.write(datap, image->getDataSize()); - U8* image_data = image->getData(); + const U8* image_data = image->getData(); for (S32 i = 0; i < image->getDataSize(); ++i) { bas << image_data[i]; From 516d7a890d1e6672fb82022b9681bb0f9c609688 Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 5 Jan 2024 00:21:14 +0000 Subject: [PATCH 13/29] Add EOL, hopefully make pre-commit happy --- scripts/messages/message_template.msg.sha1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/messages/message_template.msg.sha1 b/scripts/messages/message_template.msg.sha1 index efa5f3cf48..c99611a752 100755 --- a/scripts/messages/message_template.msg.sha1 +++ b/scripts/messages/message_template.msg.sha1 @@ -1 +1,2 @@ -d7915d67467e59287857630bd89bf9529d065199 \ No newline at end of file +d7915d67467e59287857630bd89bf9529d065199 + From d12fbf7ec19ffaf046d2bd37b05e448690f2b320 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 20 Dec 2023 17:41:03 +0100 Subject: [PATCH 14/29] Build fix for Visual Studio update (std::vector) (cherry picked from commit a7dcb0df2a11377b1112dfa0720e876507e1ae3d) --- indra/newview/llmaterialeditor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index a5437f7a88..5e78e15c72 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -2131,7 +2131,7 @@ bool LLMaterialEditor::canModifyObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_MODIFY}), permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_MODIFY}), permissions, item_out); } bool LLMaterialEditor::canSaveObjectsMaterial() @@ -2139,7 +2139,7 @@ bool LLMaterialEditor::canSaveObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item_out); } bool LLMaterialEditor::canClipboardObjectsMaterial() @@ -2165,7 +2165,7 @@ bool LLMaterialEditor::canClipboardObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), permissions, item_out); } void LLMaterialEditor::saveObjectsMaterialAs() @@ -2173,7 +2173,7 @@ void LLMaterialEditor::saveObjectsMaterialAs() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item = nullptr; - bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item); + bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), permissions, item); if (!allowed) { LL_WARNS("MaterialEditor") << "Failed to save GLTF material from object" << LL_ENDL; From f62b8591a29481ce882b1e50246f848475d3fb6a Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Fri, 5 Jan 2024 19:45:58 +0100 Subject: [PATCH 15/29] DRTVWR-489 MacOS Release build fix (vertex_count and index_count aren't used) --- indra/newview/llvotree.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 36e6da802b..575b1dbe7e 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -865,6 +865,10 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) mReferenceBuffer->unmapBuffer(); llassert(vertex_count == max_vertices); llassert(index_count == max_indices); +#ifndef SHOW_ASSERT + (void)vertex_count; + (void)index_count; +#endif } //generate tree mesh From 82d8b2a7209a96cdc38dd8e77f458cac3ffeedbd Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 5 Jan 2024 19:01:40 +0000 Subject: [PATCH 16/29] sl-20635 attempts at build fixes, added a few stray log messages about log file changes --- indra/newview/llappviewer.cpp | 1 + indra/newview/llviewercontrol.cpp | 1 + indra/newview/llviewerobject.cpp | 2 -- scripts/messages/message_template.msg.sha1 | 3 +-- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 4a43133ff6..557ee1ab16 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2342,6 +2342,7 @@ void LLAppViewer::initLoggingAndGetLastDuration() // Set the log file to SecondLife.log LLError::logToFile(log_file); + LL_INFOS() << "Started logging to " << log_file << LL_ENDL; if (!duration_log_msg.empty()) { LL_WARNS("MarkerFile") << duration_log_msg << LL_ENDL; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 7738cb904e..61cc1dee25 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -450,6 +450,7 @@ static bool handleLogFileChanged(const LLSD& newvalue) std::string log_filename = newvalue.asString(); LLFile::remove(log_filename); LLError::logToFile(log_filename); + LL_INFOS() << "Logging switched to " << log_filename << LL_ENDL; return true; } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 2669c956e1..c4e5fcc7b6 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -1340,7 +1340,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); ((LLVOAvatar*)this)->setFootPlane(collision_plane); count += sizeof(LLVector4); - [[fallthrough]]; case OBJECTDATA_FIELD_SIZE_124: case OBJECTDATA_FIELD_SIZE_60: @@ -1564,7 +1563,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, htolememcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); ((LLVOAvatar*)this)->setFootPlane(collision_plane); count += sizeof(LLVector4); - [[fallthrough]]; case OBJECTDATA_FIELD_SIZE_64: case OBJECTDATA_FIELD_SIZE_32: diff --git a/scripts/messages/message_template.msg.sha1 b/scripts/messages/message_template.msg.sha1 index c99611a752..678bd81ebe 100755 --- a/scripts/messages/message_template.msg.sha1 +++ b/scripts/messages/message_template.msg.sha1 @@ -1,2 +1 @@ -d7915d67467e59287857630bd89bf9529d065199 - +d7915d67467e59287857630bd89bf9529d065198 From eca0021b7dfd40d5b573ae5530cf44edbe3a0994 Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 5 Jan 2024 21:17:08 +0000 Subject: [PATCH 17/29] Fix VIEWER_VERSION.txt so it passes pre-commit ? --- indra/newview/VIEWER_VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 0e7b60da8a..a8a1887568 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -7.1.2 \ No newline at end of file +7.1.2 From e4a1feb83079965fbebd356aa694adf100fb7ee3 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Sun, 7 Jan 2024 14:44:52 +0100 Subject: [PATCH 18/29] SL-20743 Use LLMutex in LLImageBase for internal data thread-safety (update) --- indra/llcommon/llmutex.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index f56c2d08a6..973ecbc87b 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -196,9 +196,18 @@ void LLSharedMutex::lockExclusive() LLThread::id_t current_thread = LLThread::currentID(); mLockMutex.lock(); - if (mLockingThreads.size() == 1 && mLockingThreads.begin()->first == current_thread) + iterator it = mLockingThreads.find(current_thread); + if (it != mLockingThreads.end()) { - mLockingThreads.begin()->second++; + if (mIsShared) + { + // The mutex is already locked in the current thread + // but this lock is SHARED (not EXCLISIVE) + // We can't lock it again, the lock stays shared + // This can lead to a collision (theoretically) + llassert_always(!"The current thread is already locked SHARED and can't be locked EXCLUSIVE"); + } + it->second++; } else { From b489142cb1af0fd469c0a5cedf60040a413f4fbd Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 20 Dec 2023 17:41:03 +0100 Subject: [PATCH 19/29] Build fix for Visual Studio update (std::vector) --- indra/newview/llmaterialeditor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 9f59a13590..c066a7b5c3 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -2228,7 +2228,7 @@ bool LLMaterialEditor::canModifyObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_MODIFY}), ItemSource::OBJECT, permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_MODIFY}), ItemSource::OBJECT, permissions, item_out); } bool LLMaterialEditor::canSaveObjectsMaterial() @@ -2236,7 +2236,7 @@ bool LLMaterialEditor::canSaveObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item_out); } bool LLMaterialEditor::canClipboardObjectsMaterial() @@ -2262,7 +2262,7 @@ bool LLMaterialEditor::canClipboardObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), ItemSource::OBJECT, permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), ItemSource::OBJECT, permissions, item_out); } void LLMaterialEditor::saveObjectsMaterialAs() @@ -2270,7 +2270,7 @@ void LLMaterialEditor::saveObjectsMaterialAs() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item = nullptr; - bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item); + bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item); if (!allowed) { LL_WARNS("MaterialEditor") << "Failed to save GLTF material from object" << LL_ENDL; From 44f509a3197b95860da60e5a149bd894df79d828 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 10 Jan 2024 06:40:58 +0100 Subject: [PATCH 20/29] SL-20752 Mouselook no longer allows pitch upwards to full 90 degrees --- indra/newview/llagent.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 3853aaa8fd..e7234303a8 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -1473,8 +1473,9 @@ void LLAgent::pitch(F32 angle) // after left-clicking the mouse on the avatar and dragging down // // The issue is observed on angle below 10 degrees + bool isMouseLookOn = mControlFlags & AGENT_CONTROL_MOUSELOOK; const F32 look_down_limit = 179.f * DEG_TO_RAD; - const F32 look_up_limit = 10.f * DEG_TO_RAD; + const F32 look_up_limit = (isMouseLookOn ? 1.f : 10.f) * DEG_TO_RAD; F32 angle_from_skyward = acos(mFrameAgent.getAtAxis() * skyward); From 91a6aa95e7b6303c4fd7b2394ee2ec422f3979ba Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 10 Jan 2024 17:44:12 +0100 Subject: [PATCH 21/29] SL-20244 Maint A - On-screen animesh characters that start pelvis offset animations disappear when root goes off-screen --- indra/newview/llspatialpartition.h | 1 - indra/newview/llvovolume.cpp | 24 ------------------------ 2 files changed, 25 deletions(-) diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 758e716c00..19408ec5de 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -729,7 +729,6 @@ class LLControlAVBridge : public LLVolumeBridge using super = LLVolumeBridge; public: LLControlAVBridge(LLDrawable* drawablep, LLViewerRegion* regionp); - virtual void updateSpatialExtents(); }; class LLHUDBridge : public LLVolumeBridge diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 8846e30145..ad6c39de48 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5056,30 +5056,6 @@ LLControlAVBridge::LLControlAVBridge(LLDrawable* drawablep, LLViewerRegion* regi mPartitionType = LLViewerRegion::PARTITION_CONTROL_AV; } -void LLControlAVBridge::updateSpatialExtents() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - LLSpatialGroup* root = (LLSpatialGroup*)mOctree->getListener(0); - - bool rootWasDirty = root->isDirty(); - - super::updateSpatialExtents(); // root becomes non-dirty here - - // SL-18251 "On-screen animesh characters using pelvis offset animations - // disappear when root goes off-screen" - // - // Expand extents to include Control Avatar placed outside of the bounds - LLControlAvatar* controlAvatar = getVObj() ? getVObj()->getControlAvatar() : NULL; - if (controlAvatar - && controlAvatar->mDrawable - && controlAvatar->mDrawable->getEntry() - && (rootWasDirty || controlAvatar->mPlaying)) - { - root->expandExtents(controlAvatar->mDrawable->getSpatialExtents(), *mDrawable->getXform()); - } -} - bool can_batch_texture(LLFace* facep) { if (facep->getTextureEntry()->getBumpmap()) From da967da9c7aa0d88f478d476e8bb059ba79ca818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Thu, 11 Jan 2024 11:32:15 +0100 Subject: [PATCH 22/29] Rename OS X to macOS, mostly in comments We only support 10.13+ now, and it's been called macOS since 10.12. References in code to older versions are unchanged. --- indra/cmake/Variables.cmake | 2 +- indra/lib/python/indra/util/llmanifest.py | 4 ++-- indra/llcommon/llerror.cpp | 2 +- indra/llcommon/llsys.cpp | 6 +++--- indra/llcommon/lluuid.cpp | 2 +- indra/llfilesystem/lldir_mac.cpp | 2 +- indra/llfilesystem/lldir_mac.h | 2 +- indra/llfilesystem/lldir_utils_objc.h | 2 +- indra/llfilesystem/lldir_utils_objc.mm | 2 +- indra/llmessage/net.cpp | 2 +- indra/llrender/llfontgl.cpp | 2 +- indra/llrender/llimagegl.cpp | 2 +- indra/llwindow/llkeyboard.h | 2 +- indra/llwindow/llwindowmacosx.cpp | 4 ++-- indra/media_plugins/cef/mac_volume_catcher.cpp | 2 +- indra/media_plugins/cef/media_plugin_cef.cpp | 2 +- indra/newview/app_settings/settings.xml | 2 +- indra/newview/llappviewermacosx-objc.mm | 2 +- indra/newview/llappviewermacosx.cpp | 2 +- indra/newview/llviewerjoystick.cpp | 2 +- indra/newview/llvoicevivox.cpp | 2 +- 21 files changed, 25 insertions(+), 25 deletions(-) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index af1f16d04d..9bc17df32a 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -5,7 +5,7 @@ # # Platform variables: # -# DARWIN - Mac OS X +# DARWIN - macOS # LINUX - Linux # WINDOWS - Windows diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py index bcb9d884c3..20c0e01576 100755 --- a/indra/lib/python/indra/util/llmanifest.py +++ b/indra/lib/python/indra/util/llmanifest.py @@ -116,7 +116,7 @@ BASE_ARGUMENTS=[ dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE), dict(name='buildtype', description='Build type (i.e. Debug, Release, RelWithDebInfo).', default=None), dict(name='bundleid', - description="""The Mac OS X Bundle identifier.""", + description="""The macOS Bundle identifier.""", default="com.secondlife.indra.viewer"), dict(name='channel', description="""The channel to use for updates, packaging, settings name, etc.""", @@ -146,7 +146,7 @@ BASE_ARGUMENTS=[ dict(name='signature', description="""This specifies an identity to sign the viewer with, if any. If no value is supplied, the default signature will be used, if any. Currently - only used on Mac OS X.""", + only used on macOS.""", default=None), dict(name='source', description='Source directory.', diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 414515854a..19c285ea5a 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -700,7 +700,7 @@ namespace bool shouldLogToStderr() { #if LL_DARWIN - // On Mac OS X, stderr from apps launched from the Finder goes to the + // On macOS, stderr from apps launched from the Finder goes to the // console log. It's generally considered bad form to spam too much // there. That scenario can be detected by noticing that stderr is a // character device (S_IFCHR). diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 938685bae6..d3f99a413d 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -269,9 +269,9 @@ LLOSInfo::LLOSInfo() : #elif LL_DARWIN // Initialize mOSStringSimple to something like: - // "Mac OS X 10.6.7" + // "macOS 10.13.1" { - const char * DARWIN_PRODUCT_NAME = "Mac OS X"; + const char * DARWIN_PRODUCT_NAME = "macOS"; int64_t major_version, minor_version, bugfix_version = 0; @@ -294,7 +294,7 @@ LLOSInfo::LLOSInfo() : } // Initialize mOSString to something like: - // "Mac OS X 10.6.7 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386" + // "macOS 10.13.1 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386" struct utsname un; if(uname(&un) != -1) { diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 200add404f..285469f0d4 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -510,7 +510,7 @@ S32 LLUUID::getNodeID(unsigned char* node_id) } #elif LL_DARWIN -// Mac OS X version of the UUID generation code... +// macOS version of the UUID generation code... /* * Get an ethernet hardware address, if we can find it... */ diff --git a/indra/llfilesystem/lldir_mac.cpp b/indra/llfilesystem/lldir_mac.cpp index 9ad8e274b6..0d9695e161 100644 --- a/indra/llfilesystem/lldir_mac.cpp +++ b/indra/llfilesystem/lldir_mac.cpp @@ -1,6 +1,6 @@ /** * @file lldir_mac.cpp - * @brief Implementation of directory utilities for Mac OS X + * @brief Implementation of directory utilities for macOS * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/llfilesystem/lldir_mac.h b/indra/llfilesystem/lldir_mac.h index 558727ebbc..0290fb773b 100644 --- a/indra/llfilesystem/lldir_mac.h +++ b/indra/llfilesystem/lldir_mac.h @@ -1,6 +1,6 @@ /** * @file lldir_mac.h - * @brief Definition of directory utilities class for Mac OS X + * @brief Definition of directory utilities class for macOS * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/llfilesystem/lldir_utils_objc.h b/indra/llfilesystem/lldir_utils_objc.h index 59dbeb4aec..48148aad95 100644 --- a/indra/llfilesystem/lldir_utils_objc.h +++ b/indra/llfilesystem/lldir_utils_objc.h @@ -1,6 +1,6 @@ /** * @file lldir_utils_objc.h - * @brief Definition of directory utilities class for Mac OS X + * @brief Definition of directory utilities class for macOS * * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/llfilesystem/lldir_utils_objc.mm b/indra/llfilesystem/lldir_utils_objc.mm index 20540fb93c..01fe9e1f2c 100644 --- a/indra/llfilesystem/lldir_utils_objc.mm +++ b/indra/llfilesystem/lldir_utils_objc.mm @@ -1,6 +1,6 @@ /** * @file lldir_utils_objc.mm - * @brief Cocoa implementation of directory utilities for Mac OS X + * @brief Cocoa implementation of directory utilities for macOS * * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 523bcbb60d..60030bb920 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -77,7 +77,7 @@ const char* LOOPBACK_ADDRESS_STRING = "127.0.0.1"; const char* BROADCAST_ADDRESS_STRING = "255.255.255.255"; #if LL_DARWIN - // Mac OS X returns an error when trying to set these to 400000. Smaller values succeed. + // macOS returns an error when trying to set these to 400000. Smaller values succeed. const int SEND_BUFFER_SIZE = 200000; const int RECEIVE_BUFFER_SIZE = 200000; #else // LL_DARWIN diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 15fddbc99f..484fa9d82c 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -1110,7 +1110,7 @@ LLFontGL* LLFontGL::getFontDefault() std::string LLFontGL::getFontPathSystem() { #if LL_DARWIN - // HACK for Mac OS X + // HACK for macOS return "/System/Library/Fonts/"; #elif LL_WINDOWS diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index bbedcf360c..6315b2cd7c 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -56,7 +56,7 @@ const F32 MIN_TEXTURE_LIFETIME = 10.f; U32 wpo2(U32 i); -// texture memory accounting (for OS X) +// texture memory accounting (for macOS) static LLMutex sTexMemMutex; static std::unordered_map sTextureAllocs; static U64 sTextureBytes = 0; diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index dad150e3c1..2f80a9e89a 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -77,7 +77,7 @@ public: virtual BOOL handleKeyDown(const U16 key, MASK mask) = 0; #ifdef LL_DARWIN - // We only actually use this for OS X. + // We only actually use this for macOS. virtual void handleModifier(MASK mask) = 0; #endif // LL_DARWIN diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 778e5d3898..b317f00ae7 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1249,7 +1249,7 @@ F32 LLWindowMacOSX::getNativeAspectRatio() F32 LLWindowMacOSX::getPixelAspectRatio() { - //OS X always enforces a 1:1 pixel aspect ratio, regardless of video mode + //macOS always enforces a 1:1 pixel aspect ratio, regardless of video mode return 1.f; } @@ -1281,7 +1281,7 @@ void LLWindowMacOSX::afterDialog() void LLWindowMacOSX::flashIcon(F32 seconds) { - // For consistency with OS X conventions, the number of seconds given is ignored and + // For consistency with macOS conventions, the number of seconds given is ignored and // left up to the OS (which will actually bounce it for one second). requestUserAttention(); } diff --git a/indra/media_plugins/cef/mac_volume_catcher.cpp b/indra/media_plugins/cef/mac_volume_catcher.cpp index dddb9c2077..dafe545d09 100644 --- a/indra/media_plugins/cef/mac_volume_catcher.cpp +++ b/indra/media_plugins/cef/mac_volume_catcher.cpp @@ -1,6 +1,6 @@ /** * @file mac_volume_catcher.cpp - * @brief A Mac OS X specific hack to control the volume level of all audio channels opened by a process. + * @brief A macOS specific hack to control the volume level of all audio channels opened by a process. * * @cond * $LicenseInfo:firstyear=2010&license=viewerlgpl$ diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 43d3a32e64..d5e17ba536 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -816,7 +816,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string) S32 y = message_in.getValueS32("y"); // only even send left mouse button events to the CEF library - // (partially prompted by crash in OS X CEF when sending right button events) + // (partially prompted by crash in macOS CEF when sending right button events) // we catch the right click in viewer and display our own context menu anyway S32 button = message_in.getValueS32("button"); dullahan::EMouseButton btn = dullahan::MB_MOUSE_BUTTON_LEFT; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 00b59f9a4d..8f651a0294 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -9022,7 +9022,7 @@ RenderHiDPI Comment - Enable support for HiDPI displays, like Retina (MacOS X ONLY, requires restart) + Enable support for HiDPI displays, like Retina (macOS ONLY, requires restart) Persist 1 Type diff --git a/indra/newview/llappviewermacosx-objc.mm b/indra/newview/llappviewermacosx-objc.mm index 17301847e8..81ab4e0feb 100644 --- a/indra/newview/llappviewermacosx-objc.mm +++ b/indra/newview/llappviewermacosx-objc.mm @@ -25,7 +25,7 @@ */ #if !defined LL_DARWIN - #error "Use only with Mac OS X" + #error "Use only with macOS" #endif #import diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 8b313a321b..72e38cc1ea 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -27,7 +27,7 @@ #include "llviewerprecompiledheaders.h" #if !defined LL_DARWIN - #error "Use only with Mac OS X" + #error "Use only with macOS" #endif #define LL_CARBON_CRASH_HANDLER 1 diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index e35cb26ce1..dfa47e82b3 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -1414,7 +1414,7 @@ void LLViewerJoystick::setSNDefaults() #if LL_DARWIN || LL_LINUX const float platformScale = 20.f; const float platformScaleAvXZ = 1.f; - // The SpaceNavigator doesn't act as a 3D cursor on OS X / Linux. + // The SpaceNavigator doesn't act as a 3D cursor on macOS / Linux. const bool is_3d_cursor = false; #else const float platformScale = 1.f; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 3725510b6a..c4cd1779b7 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -5314,7 +5314,7 @@ std::string LLVivoxVoiceClient::nameFromID(const LLUUID &uuid) LLStringUtil::replaceChar(result, '+', '-'); LLStringUtil::replaceChar(result, '/', '_'); - // If you need to transform a GUID to this form on the Mac OS X command line, this will do so: + // If you need to transform a GUID to this form on the macOS command line, this will do so: // echo -n x && (echo e669132a-6c43-4ee1-a78d-6c82fff59f32 |xxd -r -p |openssl base64|tr '/+' '_-') // The reverse transform can be done with: From 4a03aa089009af9130076b438192e338bc202584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Thu, 11 Jan 2024 20:36:17 +0100 Subject: [PATCH 23/29] operatingSystemVersion and NSOperatingSystemVersion exis since OS X 10.10, and we require macOS 10.13+ now --- indra/llcommon/llsys_objc.mm | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/indra/llcommon/llsys_objc.mm b/indra/llcommon/llsys_objc.mm index 3fd85fb1c9..1393ccea50 100644 --- a/indra/llcommon/llsys_objc.mm +++ b/indra/llcommon/llsys_objc.mm @@ -27,38 +27,12 @@ #import "llsys_objc.h" #import -static auto intAtStringIndex(NSArray *array, int index) -{ - return [(NSString *)[array objectAtIndex:index] integerValue]; -} - bool LLGetDarwinOSInfo(int64_t &major, int64_t &minor, int64_t &patch) { - if (NSAppKitVersionNumber > NSAppKitVersionNumber10_8) - { NSOperatingSystemVersion osVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; major = osVersion.majorVersion; minor = osVersion.minorVersion; patch = osVersion.patchVersion; - } - else - { - NSString* versionString = [[NSDictionary dictionaryWithContentsOfFile: - @"/System/Library/CoreServices/SystemVersion.plist"] objectForKey:@"ProductVersion"]; - NSArray* versions = [versionString componentsSeparatedByString:@"."]; - NSUInteger count = [versions count]; - if (count > 0) - { - major = intAtStringIndex(versions, 0); - if (count > 1) - { - minor = intAtStringIndex(versions, 1); - if (count > 2) - { - patch = intAtStringIndex(versions, 2); - } - } - } - } + return true; } From 0249eefe53f2267a179a1271ae21b9c9af878ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Thu, 11 Jan 2024 22:54:30 +0100 Subject: [PATCH 24/29] Locale problems prior to OS X 10.4 no longer apply localeconv() returns the right values in later versions, and we only support 10.13+ --- indra/llui/llresmgr.cpp | 55 ----------------------------------------- 1 file changed, 55 deletions(-) diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp index d65c220974..23e0842f37 100644 --- a/indra/llui/llresmgr.cpp +++ b/indra/llui/llresmgr.cpp @@ -51,14 +51,6 @@ char LLResMgr::getDecimalPoint() const { char decimal = localeconv()->decimal_point[0]; -#if LL_DARWIN - // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. - if(decimal == 0) - { - decimal = '.'; - } -#endif - return decimal; } @@ -66,14 +58,6 @@ char LLResMgr::getThousandsSeparator() const { char separator = localeconv()->thousands_sep[0]; -#if LL_DARWIN - // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. - if(separator == 0) - { - separator = ','; - } -#endif - return separator; } @@ -81,14 +65,6 @@ char LLResMgr::getMonetaryDecimalPoint() const { char decimal = localeconv()->mon_decimal_point[0]; -#if LL_DARWIN - // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. - if(decimal == 0) - { - decimal = '.'; - } -#endif - return decimal; } @@ -96,14 +72,6 @@ char LLResMgr::getMonetaryThousandsSeparator() const { char separator = localeconv()->mon_thousands_sep[0]; -#if LL_DARWIN - // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. - if(separator == 0) - { - separator = ','; - } -#endif - return separator; } @@ -115,29 +83,6 @@ std::string LLResMgr::getMonetaryString( S32 input ) const LLLocale locale(LLLocale::USER_LOCALE); struct lconv *conv = localeconv(); - -#if LL_DARWIN - // On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. - // Fake up a conv structure with some reasonable values for the fields this function uses. - struct lconv fakeconv; - char fake_neg[2] = "-"; - char fake_mon_group[4] = "\x03\x03\x00"; // commas every 3 digits - if(conv->negative_sign[0] == 0) // Real locales all seem to have something here... - { - fakeconv = *conv; // start with what's there. - switch(mLocale) - { - default: // Unknown -- use the US defaults. - case LLLOCALE_USA: - case LLLOCALE_UK: // UK ends up being the same as US for the items used here. - fakeconv.negative_sign = fake_neg; - fakeconv.mon_grouping = fake_mon_group; - fakeconv.n_sign_posn = 1; // negative sign before the string - break; - } - conv = &fakeconv; - } -#endif char* negative_sign = conv->negative_sign; char separator = getMonetaryThousandsSeparator(); From 469f2621f170484943093a830ec385f1b8d20934 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Wed, 17 Jan 2024 00:30:37 +0200 Subject: [PATCH 25/29] SL-20708 don't reset "Quality & speed" slider when canceling Advanced Settings --- indra/newview/llfloaterpreference.cpp | 23 ++++++++++++------- indra/newview/llfloaterpreference.h | 10 ++++---- .../llfloaterpreferencesgraphicsadvanced.cpp | 2 +- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index aa723eb3a8..d15c52cc24 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -620,7 +620,7 @@ void LLFloaterPreference::apply() saveAvatarProperties(); } -void LLFloaterPreference::cancel() +void LLFloaterPreference::cancel(const std::vector settings_to_skip) { LLTabContainer* tabcontainer = getChild("pref core"); // Call cancel() on all panels that derive from LLPanelPreference @@ -630,7 +630,7 @@ void LLFloaterPreference::cancel() LLView* view = *iter; LLPanelPreference* panel = dynamic_cast(view); if (panel) - panel->cancel(); + panel->cancel(settings_to_skip); } // hide joystick pref floater LLFloaterReg::hideInstance("pref_joystick"); @@ -1011,15 +1011,16 @@ void LLFloaterPreference::onBtnCancel(const LLSD& userdata) } refresh(); } - cancel(); - + if (userdata.asString() == "closeadvanced") { + cancel({"RenderQualityPerformance"}); LLFloaterReg::hideInstance("prefs_graphics_advanced"); updateMaxComplexity(); } else { + cancel(); closeFloater(); } } @@ -2206,7 +2207,7 @@ void LLPanelPreference::toggleMuteWhenMinimized() } } -void LLPanelPreference::cancel() +void LLPanelPreference::cancel(const std::vector settings_to_skip) { for (control_values_map_t::iterator iter = mSavedValues.begin(); iter != mSavedValues.end(); ++iter) @@ -2219,6 +2220,12 @@ void LLPanelPreference::cancel() continue; } + auto found = std::find(settings_to_skip.begin(), settings_to_skip.end(), control->getName()); + if (found != settings_to_skip.end()) + { + continue; + } + control->set(ctrl_value); } @@ -2461,9 +2468,9 @@ void LLPanelPreferenceGraphics::resetDirtyChilds() } } -void LLPanelPreferenceGraphics::cancel() +void LLPanelPreferenceGraphics::cancel(const std::vector settings_to_skip) { - LLPanelPreference::cancel(); + LLPanelPreference::cancel(settings_to_skip); } void LLPanelPreferenceGraphics::saveSettings() { @@ -2751,7 +2758,7 @@ void LLPanelPreferenceControls::apply() } } -void LLPanelPreferenceControls::cancel() +void LLPanelPreferenceControls::cancel(const std::vector settings_to_skip) { for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i) { diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 04ac87364d..bdade3c1b9 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -79,7 +79,7 @@ public: ~LLFloaterPreference(); void apply(); - void cancel(); + void cancel(const std::vector settings_to_skip = {}); /*virtual*/ void draw(); /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); @@ -251,7 +251,7 @@ public: virtual ~LLPanelPreference(); virtual void apply(); - virtual void cancel(); + virtual void cancel(const std::vector settings_to_skip = {}); void setControlFalse(const LLSD& user_data); virtual void setHardwareDefaults(); @@ -294,14 +294,12 @@ class LLPanelPreferenceGraphics : public LLPanelPreference public: BOOL postBuild(); void draw(); - void cancel(); + void cancel(const std::vector settings_to_skip = {}); void saveSettings(); void resetDirtyChilds(); void setHardwareDefaults(); void setPresetText(); - static const std::string getPresetsPath(); - protected: bool hasDirtyChilds(); @@ -320,7 +318,7 @@ public: BOOL postBuild(); void apply(); - void cancel(); + void cancel(const std::vector settings_to_skip = {}); void saveSettings(); void resetDirtyChilds(); diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp index a91f0ec060..f83ce868a3 100644 --- a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp @@ -93,7 +93,7 @@ void LLFloaterPreferenceGraphicsAdvanced::onClickCloseBtn(bool app_quitting) LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); if (instance) { - instance->cancel(); + instance->cancel({"RenderQualityPerformance"}); } updateMaxComplexity(); } From 1769dc9a62f86a0a1052046cc36e6592895dbc60 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 31 Jan 2024 20:28:45 +0100 Subject: [PATCH 26/29] GH-141872 Ability to drag Favorites to the Landmarks panel --- indra/newview/lltooldraganddrop.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index e7f96239fd..055058e4eb 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -47,6 +47,7 @@ #include "llinventorybridge.h" #include "llinventorydefines.h" #include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" #include "llpreviewnotecard.h" #include "llrootview.h" #include "llselectmgr.h" @@ -320,6 +321,16 @@ void LLToolDragAndDrop::beginDrag(EDragAndDropType type, LL_WARNS() << "Attempted to start drag without a cargo type" << LL_ENDL; return; } + + if (type != DAD_CATEGORY) + { + LLViewerInventoryItem* item = gInventory.getItem(cargo_id); + if (item && !item->isFinished()) + { + LLInventoryModelBackgroundFetch::instance().start(item->getUUID(), false); + } + } + mCargoTypes.clear(); mCargoTypes.push_back(type); mCargoIDs.clear(); From 584ccc2f84e010cbf5cadad5da7651577b51946c Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 5 Feb 2024 12:56:00 +0100 Subject: [PATCH 27/29] #68175 PR-726 MacOS build fix --- indra/llui/lluictrl.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index be1c7dd0b6..f1b6746ea0 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -146,24 +146,24 @@ protected: // We shouldn't ever need to set this directly //virtual void setViewModel(const LLViewModelPtr&); - virtual BOOL postBuild(); + /*virtual*/ BOOL postBuild() override; public: // LLView interface - /*virtual*/ BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - /*virtual*/ BOOL isCtrl() const; - /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask); - /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL canFocusChildren() const; - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ) override; + /*virtual*/ BOOL isCtrl() const override; + /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask) override; + /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL canFocusChildren() const override; + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask) override; // From LLFocusableElement - /*virtual*/ void setFocus( BOOL b ); - /*virtual*/ BOOL hasFocus() const; + /*virtual*/ void setFocus( BOOL b ) override; + /*virtual*/ BOOL hasFocus() const override; // New virtuals @@ -318,7 +318,7 @@ protected: static F32 sActiveControlTransparency; static F32 sInactiveControlTransparency; - virtual void addInfo(LLSD & info); + /*virtual*/ void addInfo(LLSD & info) override; private: From 7fa86e04d6ce9081e364d67ffd4efd010eb46d81 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Tue, 6 Feb 2024 01:21:10 +0200 Subject: [PATCH 28/29] SL-19730 Bulk Pick Up Single Items --- indra/newview/llviewermenu.cpp | 67 ++++++++++++++++++- indra/newview/llviewermenu.h | 2 +- .../skins/default/xui/en/menu_object.xml | 22 ++++++ 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 9db9d97ddc..be48d1c5e2 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -233,6 +233,7 @@ BOOL enable_take(); void handle_object_show_inspector(); void handle_avatar_show_inspector(); bool confirm_take(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection_handle); +bool confirm_take_separate(const LLSD ¬ification, const LLSD &response, LLObjectSelectionHandle selection_handle); void handle_buy_object(LLSaleInfo sale_info); void handle_buy_contents(LLSaleInfo sale_info); @@ -4866,6 +4867,24 @@ static void derez_objects(EDeRezDestination dest, const LLUUID& dest_id) derez_objects(dest, dest_id, first_region, error, NULL); } +static void derez_objects_separate(EDeRezDestination dest, const LLUUID &dest_id) +{ + std::vector derez_object_list; + std::string error; + LLViewerRegion* first_region = NULL; + if (!get_derezzable_objects(dest, error, first_region, &derez_object_list, false)) + { + LL_WARNS() << "No objects to derez" << LL_ENDL; + return; + } + for (LLViewerObject *opjectp : derez_object_list) + { + std::vector buf_list; + buf_list.push_back(opjectp); + derez_objects(dest, dest_id, first_region, error, &buf_list); + } +} + void handle_take_copy() { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; @@ -4874,6 +4893,15 @@ void handle_take_copy() derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); } +void handle_take_separate_copy() +{ + if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) + return; + + const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); + derez_objects_separate(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); +} + void handle_link_objects() { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) @@ -4967,7 +4995,7 @@ void force_take_copy(void*) derez_objects(DRD_FORCE_TO_GOD_INVENTORY, category_id); } -void handle_take() +void handle_take(bool take_separate) { // we want to use the folder this was derezzed from if it's // available. Otherwise, derez to the normal place. @@ -5056,7 +5084,17 @@ void handle_take() // MAINT-290 // Reason: Showing the confirmation dialog resets object selection, thus there is nothing to derez. // Fix: pass selection to the confirm_take, so that selection doesn't "die" after confirmation dialog is opened - params.functor.function(boost::bind(confirm_take, _1, _2, LLSelectMgr::instance().getSelection())); + params.functor.function([take_separate](const LLSD ¬ification, const LLSD &response) + { + if (take_separate) + { + confirm_take_separate(notification, response, LLSelectMgr::instance().getSelection()); + } + else + { + confirm_take(notification, response, LLSelectMgr::instance().getSelection()); + } + }); if(locked_but_takeable_object || !you_own_everything) @@ -5119,6 +5157,16 @@ bool confirm_take(const LLSD& notification, const LLSD& response, LLObjectSelect return false; } +bool confirm_take_separate(const LLSD ¬ification, const LLSD &response, LLObjectSelectionHandle selection_handle) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (enable_take() && (option == 0)) + { + derez_objects_separate(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID()); + } + return false; +} + // You can take an item when it is public and transferrable, or when // you own it. We err on the side of enabling the item when at least // one item selected can be copied to inventory. @@ -5201,6 +5249,11 @@ bool visible_take_object() return !is_selection_buy_not_take() && enable_take(); } +bool visible_take_objects() +{ + return visible_take_object() && (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 1); +} + bool tools_visible_buy_object() { return is_selection_buy_not_take(); @@ -7968,6 +8021,10 @@ bool enable_object_take_copy() return all_valid; } +bool visible_take_copy_objects() +{ + return enable_object_take_copy() && (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() > 1); +} class LLHasAsset : public LLInventoryCollectFunctor { @@ -9438,6 +9495,7 @@ void initialize_menus() enable.add("Tools.EnableUnlink", boost::bind(&LLSelectMgr::enableUnlinkObjects, LLSelectMgr::getInstance())); view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake"); enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy)); + enable.add("Tools.VisibleCopySeparate", boost::bind(&visible_take_copy_objects)); enable.add("Tools.VisibleBuyObject", boost::bind(&tools_visible_buy_object)); enable.add("Tools.VisibleTakeObject", boost::bind(&tools_visible_take_object)); view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory"); @@ -9698,6 +9756,7 @@ void initialize_menus() view_listener_t::addMenu(new LLObjectMute(), "Object.Mute"); enable.add("Object.VisibleTake", boost::bind(&visible_take_object)); + enable.add("Object.VisibleTakeMultiple", boost::bind(&visible_take_objects)); enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object)); commit.add("Object.Buy", boost::bind(&handle_buy)); @@ -9706,7 +9765,9 @@ void initialize_menus() commit.add("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material)); commit.add("Object.Inspect", boost::bind(&handle_object_inspect)); commit.add("Object.Open", boost::bind(&handle_object_open)); - commit.add("Object.Take", boost::bind(&handle_take)); + commit.add("Object.Take", boost::bind(&handle_take, false)); + commit.add("Object.TakeSeparate", boost::bind(&handle_take, true)); + commit.add("Object.TakeSeparateCopy", boost::bind(&handle_take_separate_copy)); commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector)); enable.add("Object.EnableInspect", boost::bind(&enable_object_inspect)); enable.add("Object.EnableEditGLTFMaterial", boost::bind(&enable_object_edit_gltf_material)); diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index 7142763451..b1ab7a2688 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -103,7 +103,7 @@ bool enable_object_delete(); // Buy either contents or object itself void handle_buy(); -void handle_take(); +void handle_take(bool take_separate = false); void handle_take_copy(); void handle_look_at_selection(const LLSD& param); void handle_zoom_to_object(LLUUID object_id); diff --git a/indra/newview/skins/default/xui/en/menu_object.xml b/indra/newview/skins/default/xui/en/menu_object.xml index 5507c9f3a1..ab8aaf4688 100644 --- a/indra/newview/skins/default/xui/en/menu_object.xml +++ b/indra/newview/skins/default/xui/en/menu_object.xml @@ -183,6 +183,28 @@ + + + + + + + + + + Date: Fri, 2 Feb 2024 19:53:08 +0100 Subject: [PATCH 29/29] GH-68175 [SL-17986] Ability to drag Favorites to the Overflow menu --- indra/newview/llfavoritesbar.cpp | 370 ++++++++++++++++++++----------- indra/newview/llfavoritesbar.h | 39 ++-- 2 files changed, 254 insertions(+), 155 deletions(-) diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index cdce6f7156..f926a8a6d5 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -79,7 +79,7 @@ public: } void setLandmarkID(const LLUUID& id) { mLandmarkID = id; } - const LLUUID& getLandmarkId() const { return mLandmarkID; } + const LLUUID& getLandmarkID() const { return mLandmarkID; } const std::string& getName() { @@ -192,7 +192,7 @@ public: } void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); } - const LLUUID& getLandmarkId() const { return mLandmarkInfoGetter.getLandmarkId(); } + const LLUUID& getLandmarkID() const { return mLandmarkInfoGetter.getLandmarkID(); } void onMouseEnter(S32 x, S32 y, MASK mask) { @@ -237,7 +237,8 @@ public: return TRUE; } - void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); } + const LLUUID& getLandmarkID() const { return mLandmarkInfoGetter.getLandmarkID(); } + void setLandmarkID(const LLUUID& id) { mLandmarkInfoGetter.setLandmarkID(id); } virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) { @@ -285,15 +286,44 @@ private: class LLFavoriteLandmarkToggleableMenu : public LLToggleableMenu { public: - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) - { - *accept = ACCEPT_NO; - return TRUE; - } + // virtual + BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, + void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) override + { + mToolbar->handleDragAndDropToMenu(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + return TRUE; + } + + // virtual + BOOL handleHover(S32 x, S32 y, MASK mask) override + { + mIsHovering = true; + LLToggleableMenu::handleHover(x, y, mask); + mIsHovering = false; + return TRUE; + } + + // virtual + void setVisible(BOOL visible) override + { + // Avoid of hiding the menu during hovering + if (visible || !mIsHovering) + { + LLToggleableMenu::setVisible(visible); + } + } + + void setToolbar(LLFavoritesBarCtrl* toolbar) + { + mToolbar = toolbar; + } + + ~LLFavoriteLandmarkToggleableMenu() + { + // Enable subsequent setVisible(FALSE) + mIsHovering = false; + setVisible(FALSE); + } protected: LLFavoriteLandmarkToggleableMenu(const LLToggleableMenu::Params& p): @@ -301,6 +331,10 @@ protected: { } +private: + LLFavoritesBarCtrl* mToolbar { nullptr }; + bool mIsHovering { false }; + friend class LLUICtrlFactory; }; @@ -378,12 +412,12 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) mOverflowMenuHandle(), mContextMenuHandle(), mImageDragIndication(p.image_drag_indication), - mShowDragMarker(FALSE), + mShowDragMarker(false), mLandingTab(NULL), mLastTab(NULL), - mTabsHighlightEnabled(TRUE), mUpdateDropDownItems(true), mRestoreOverflowMenu(false), + mDragToOverflowMenu(false), mGetPrevItems(true), mMouseX(0), mMouseY(0), @@ -416,17 +450,16 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) LLFavoritesBarCtrl::~LLFavoritesBarCtrl() { - gInventory.removeObserver(this); + gInventory.removeObserver(this); - if (mOverflowMenuHandle.get()) mOverflowMenuHandle.get()->die(); - if (mContextMenuHandle.get()) mContextMenuHandle.get()->die(); + if (mOverflowMenuHandle.get()) + mOverflowMenuHandle.get()->die(); + if (mContextMenuHandle.get()) + mContextMenuHandle.get()->die(); } BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) + EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) { *accept = ACCEPT_NO; @@ -452,26 +485,52 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, // Copy the item into the favorites folder (if it's not already there). LLInventoryItem *item = (LLInventoryItem *)cargo_data; - if (LLFavoriteLandmarkButton* dest = dynamic_cast(findChildByLocalCoords(x, y))) + if (mDragToOverflowMenu) { - setLandingTab(dest); + LLView* overflow_menu = mOverflowMenuHandle.get(); + if (overflow_menu && !overflow_menu->isDead() && overflow_menu->getVisible()) + { + overflow_menu->handleHover(x, y, mask); + } } - else if (mLastTab && (x >= mLastTab->getRect().mRight)) + else // Drag to the toolbar itself { - /* - * the condition dest == NULL can be satisfied not only in the case - * of dragging to the right from the last tab of the favbar. there is a - * small gap between each tab. if the user drags something exactly there - * then mLandingTab will be set to NULL and the dragged item will be pushed - * to the end of the favorites bar. this is incorrect behavior. that's why - * we need an additional check which excludes the case described previously - * making sure that the mouse pointer is beyond the last tab. - */ - setLandingTab(NULL); + // Drag to a landmark button? + if (LLFavoriteLandmarkButton* dest = dynamic_cast(findChildByLocalCoords(x, y))) + { + setLandingTab(dest); + } + else + { + // Drag to the "More" button? + if (mMoreTextBox && mMoreTextBox->getVisible() && mMoreTextBox->getRect().pointInRect(x, y)) + { + LLView* overflow_menu = mOverflowMenuHandle.get(); + if (!overflow_menu || overflow_menu->isDead() || !overflow_menu->getVisible()) + { + showDropDownMenu(); + } + } + + // Drag to the right of the last landmark button? + if (mLastTab && (x >= mLastTab->getRect().mRight)) + { + /* + * the condition dest == NULL can be satisfied not only in the case + * of dragging to the right from the last tab of the favbar. there is a + * small gap between each tab. if the user drags something exactly there + * then mLandingTab will be set to NULL and the dragged item will be pushed + * to the end of the favorites bar. this is incorrect behavior. that's why + * we need an additional check which excludes the case described previously + * making sure that the mouse pointer is beyond the last tab. + */ + setLandingTab(NULL); + } + } } - // check if we are dragging an existing item from the favorites bar - bool existing_drop = false; + // Check whether we are dragging an existing item from the favorites bar + bool existing_item = false; if (item && mDragItemId == item->getUUID()) { // There is a chance of mDragItemId being obsolete @@ -479,21 +538,19 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, // results in viewer not geting a 'mouse up' signal for (LLInventoryModel::item_array_t::iterator i = mItems.begin(); i != mItems.end(); ++i) { - LLViewerInventoryItem* currItem = *i; - - if (currItem->getUUID() == mDragItemId) + if ((*i)->getUUID() == mDragItemId) { - existing_drop = true; + existing_item = true; break; } } } - if (existing_drop) + if (existing_item) { *accept = ACCEPT_YES_SINGLE; - showDragMarker(TRUE); + showDragMarker(true); if (drop) { @@ -511,14 +568,14 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, *accept = ACCEPT_YES_COPY_MULTI; - showDragMarker(TRUE); + showDragMarker(true); if (drop) { if (mItems.empty()) { setLandingTab(NULL); - mLastTab = NULL; + mLastTab = NULL; } handleNewFavoriteDragAndDrop(item, favorites_id, x, y); } @@ -532,82 +589,56 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, return TRUE; } +bool LLFavoritesBarCtrl::handleDragAndDropToMenu(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) +{ + mDragToOverflowMenu = true; + BOOL handled = handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + mDragToOverflowMenu = false; + return handled; +} + void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y) { - if (mItems.empty()) - { - // Isn't supposed to be empty + if (LL_UNLIKELY(mItems.empty())) return; + + LLUUID target_id; + bool insert_before = false; + if (!findDragAndDropTarget(target_id, insert_before, x, y)) + return; + + // There is no need to handle if an item was dragged onto itself + if (target_id == mDragItemId) + return; + + // Move the dragged item to the right place in the array + LLInventoryModel::updateItemsOrder(mItems, mDragItemId, target_id, insert_before); + LLFavoritesOrderStorage::instance().saveItemsOrder(mItems); + + LLView* menu = mOverflowMenuHandle.get(); + if (menu && !menu->isDead() && menu->getVisible()) + { + updateOverflowMenuItems(); + positionAndShowOverflowMenu(); } - - // Identify the button hovered and the side to drop - LLFavoriteLandmarkButton* dest = dynamic_cast(mLandingTab); - bool insert_before = true; - if (!dest) - { - insert_before = false; - dest = dynamic_cast(mLastTab); - } - - // There is no need to handle if an item was dragged onto itself - if (dest && dest->getLandmarkId() == mDragItemId) - { - return; - } - - // Insert the dragged item in the right place - if (dest) - { - LLInventoryModel::updateItemsOrder(mItems, mDragItemId, dest->getLandmarkId(), insert_before); - } - else - { - // This can happen when the item list is empty - mItems.push_back(gInventory.getItem(mDragItemId)); - } - - LLFavoritesOrderStorage::instance().saveItemsOrder(mItems); - - LLToggleableMenu* menu = (LLToggleableMenu*) mOverflowMenuHandle.get(); - - if (menu && menu->getVisible()) - { - menu->setVisible(FALSE); - showDropDownMenu(); - } } void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y) { // Identify the button hovered and the side to drop - LLFavoriteLandmarkButton* dest = NULL; - bool insert_before = true; - if (!mItems.empty()) - { - // [MAINT-2386] When multiple landmarks are selected and dragged onto an empty favorites bar, - // the viewer would crash when casting mLastTab below, as mLastTab is still null when the - // second landmark is being added. - // To ensure mLastTab is valid, we need to call updateButtons() at the end of this function - dest = dynamic_cast(mLandingTab); - if (!dest) - { - insert_before = false; - dest = dynamic_cast(mLastTab); - } - } - - // There is no need to handle if an item was dragged onto itself - if (dest && dest->getLandmarkId() == mDragItemId) - { - return; - } - + LLUUID target_id; + bool insert_before = false; + // There is no need to handle if an item was dragged onto itself + if (findDragAndDropTarget(target_id, insert_before, x, y) && (target_id == mDragItemId)) + return; + LLPointer viewer_item = new LLViewerInventoryItem(item); - // Insert the dragged item in the right place - if (dest) + // Insert the dragged item to the right place + if (target_id.notNull()) { - insertItem(mItems, dest->getLandmarkId(), viewer_item, insert_before); + insertItem(mItems, target_id, viewer_item, insert_before); } else { @@ -663,10 +694,75 @@ void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, con // This also ensures that mLastTab will be valid when dropping multiple // landmarks to an empty favorites bar. updateButtons(); - + + LLView* overflow_menu = mOverflowMenuHandle.get(); + if (overflow_menu && !overflow_menu->isDead() && overflow_menu->getVisible()) + { + updateOverflowMenuItems(); + positionAndShowOverflowMenu(); + } + LL_INFOS("FavoritesBar") << "Copied inventory item #" << item->getUUID() << " to favorites." << LL_ENDL; } +bool LLFavoritesBarCtrl::findDragAndDropTarget(LLUUID& target_id, bool& insert_before, S32 x, S32 y) +{ + if (mItems.empty()) + return false; + + if (mDragToOverflowMenu) + { + LLView* overflow_menu = mOverflowMenuHandle.get(); + if (LL_UNLIKELY(!overflow_menu || overflow_menu->isDead() || !overflow_menu->getVisible())) + return false; + + // Identify the menu item hovered and the side to drop + LLFavoriteLandmarkMenuItem* target_item = dynamic_cast(overflow_menu->childFromPoint(x, y)); + if (target_item) + { + insert_before = true; + } + else + { + // Choose the bottom landmark menu item + auto begin = overflow_menu->getChildList()->begin(); + auto end = overflow_menu->getChildList()->end(); + auto check = [](const LLView* child) -> bool + { + return dynamic_cast(child); + }; + // Menu items are placed in the backward order, so the bottom goes first + auto it = std::find_if(begin, end, check); + if (LL_UNLIKELY(it == end)) + return false; + target_item = (LLFavoriteLandmarkMenuItem*)*it; + insert_before = false; + } + target_id = target_item->getLandmarkID(); + } + else + { + // Identify the button hovered and the side to drop + LLFavoriteLandmarkButton* hovered_button = dynamic_cast(mLandingTab); + if (hovered_button) + { + insert_before = true; + } + else + { + // Choose the right landmark button + hovered_button = dynamic_cast(mLastTab); + if (LL_UNLIKELY(!hovered_button)) + return false; + + insert_before = false; + } + target_id = hovered_button->getLandmarkID(); + } + + return true; +} + //virtual void LLFavoritesBarCtrl::changed(U32 mask) { @@ -737,7 +833,7 @@ void LLFavoritesBarCtrl::draw() mImageDragIndication->draw(rect.mRight, rect.getHeight(), w, h); } // Once drawn, mark this false so we won't draw it again (unless we hit the favorite bar again) - mShowDragMarker = FALSE; + mShowDragMarker = false; } if (mItemsChangedTimer.getStarted()) { @@ -833,7 +929,7 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) if (item) { // an child's order and mItems should be same - if (button->getLandmarkId() != item->getUUID() // sort order has been changed + if (button->getLandmarkID() != item->getUUID() // sort order has been changed || button->getLabelSelected() != item->getName()) // favorite's name has been changed { break; @@ -907,11 +1003,7 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) { // mMoreTextBox was removed, so LLFavoriteLandmarkButtons // should be the only ones in the list - LLFavoriteLandmarkButton* button = dynamic_cast (childs->back()); - if (button) - { - mLastTab = button; - } + mLastTab = dynamic_cast(childs->back()); } mFirstDropDownItem = j; @@ -919,15 +1011,13 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update) if (mFirstDropDownItem < mItems.size()) { // if updateButton had been called it means: - //or there are some new favorites, or width had been changed + // or there are some new favorites, or width had been changed // so if we need to display chevron button, we must update dropdown items too. mUpdateDropDownItems = true; S32 buttonHGap = button_params.rect.left; // default value - LLRect rect; // Chevron button should stay right aligned - rect.setOriginAndSize(getRect().mRight - mMoreTextBox->getRect().getWidth() - buttonHGap, 0, - mMoreTextBox->getRect().getWidth(), - mMoreTextBox->getRect().getHeight()); + LLRect rect(mMoreTextBox->getRect()); + rect.translate(getRect().mRight - rect.mRight - buttonHGap, 0); addChild(mMoreTextBox); mMoreTextBox->setRect(rect); @@ -1060,14 +1150,16 @@ void LLFavoritesBarCtrl::showDropDownMenu() { if (mUpdateDropDownItems) { - updateMenuItems(menu); + updateOverflowMenuItems(); + } + else + { + menu->buildDrawLabels(); } - menu->buildDrawLabels(); menu->updateParent(LLMenuGL::sMenuContainer); menu->setButtonRect(mMoreTextBox->getRect(), this); - positionAndShowMenu(menu); - mDropDownItemsCount = menu->getItemCount(); + positionAndShowOverflowMenu(); } } @@ -1081,12 +1173,14 @@ void LLFavoritesBarCtrl::createOverflowMenu() menu_p.max_scrollable_items = 10; menu_p.preferred_width = DROP_DOWN_MENU_WIDTH; - LLToggleableMenu* menu = LLUICtrlFactory::create(menu_p); + LLFavoriteLandmarkToggleableMenu* menu = LLUICtrlFactory::create(menu_p); + menu->setToolbar(this); mOverflowMenuHandle = menu->getHandle(); } -void LLFavoritesBarCtrl::updateMenuItems(LLToggleableMenu* menu) +void LLFavoritesBarCtrl::updateOverflowMenuItems() { + LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get(); menu->empty(); U32 widest_item = 0; @@ -1115,6 +1209,8 @@ void LLFavoritesBarCtrl::updateMenuItems(LLToggleableMenu* menu) menu->addChild(menu_item); } + menu->buildDrawLabels(); + mDropDownItemsCount = menu->getItemCount(); addOpenLandmarksMenuItem(menu); mUpdateDropDownItems = false; } @@ -1171,8 +1267,9 @@ void LLFavoritesBarCtrl::addOpenLandmarksMenuItem(LLToggleableMenu* menu) menu->addChild(menu_item); } -void LLFavoritesBarCtrl::positionAndShowMenu(LLToggleableMenu* menu) +void LLFavoritesBarCtrl::positionAndShowOverflowMenu() { + LLToggleableMenu* menu = (LLToggleableMenu*)mOverflowMenuHandle.get(); U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth()); S32 menu_x = getRect().getWidth() - max_width; @@ -1460,7 +1557,7 @@ void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 } mDragItemId = id; - mStartDrag = TRUE; + mStartDrag = true; S32 screenX, screenY; localPointToScreen(x, y, &screenX, &screenY); @@ -1470,7 +1567,7 @@ void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 void LLFavoritesBarCtrl::onButtonMouseUp(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) { - mStartDrag = FALSE; + mStartDrag = false; mDragItemId = LLUUID::null; } @@ -1478,7 +1575,7 @@ void LLFavoritesBarCtrl::onEndDrag() { mEndDragConnection.disconnect(); - showDragMarker(FALSE); + showDragMarker(false); mDragItemId = LLUUID::null; LLView::getWindow()->setCursor(UI_CURSOR_ARROW); } @@ -1496,7 +1593,7 @@ BOOL LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask) DAD_LANDMARK, mDragItemId, LLToolDragAndDrop::SOURCE_LIBRARY); - mStartDrag = FALSE; + mStartDrag = false; return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask); } @@ -1525,6 +1622,7 @@ LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y) } } } + return ctrl; } @@ -2134,8 +2232,10 @@ bool LLFavoritesOrderStorage::isStorageUpdateNeeded() void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id) { - if (mTargetLandmarkId.isNull()) return; - - LLFavoritesOrderStorage::instance().rearrangeFavoriteLandmarks(inv_item_id, mTargetLandmarkId); + if (!mTargetLandmarkId.isNull()) + { + LLFavoritesOrderStorage::instance().rearrangeFavoriteLandmarks(inv_item_id, mTargetLandmarkId); + } } + // EOF diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index 3b439b31fd..6b9f2cee69 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -56,22 +56,21 @@ protected: public: virtual ~LLFavoritesBarCtrl(); - /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL postBuild() override; /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); + EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) override; + bool handleDragAndDropToMenu(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg); - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; // LLInventoryObserver observer trigger - virtual void changed(U32 mask); - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - virtual void draw(); + /*virtual*/ void changed(U32 mask) override; + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; + /*virtual*/ void draw() override; - void showDragMarker(BOOL show) { mShowDragMarker = show; } + void showDragMarker(bool show) { mShowDragMarker = show; } void setLandingTab(LLUICtrl* tab) { mLandingTab = tab; } protected: @@ -108,7 +107,7 @@ protected: S32 mDropDownItemsCount; bool mUpdateDropDownItems; bool mRestoreOverflowMenu; - + bool mDragToOverflowMenu; bool mGetPrevItems; LLUUID mSelectedItemID; @@ -118,19 +117,21 @@ protected: private: /* * Helper function to make code more readable. It handles all drag and drop - * operations of the existing favorites items on the favorites bar. + * operations of the existing favorites items to the favorites bar to on the overflow menu. */ void handleExistingFavoriteDragAndDrop(S32 x, S32 y); /* * Helper function to make code more readable. It handles all drag and drop - * operations of the new landmark to the favorites bar. + * operations of the new landmark to the favorites bar or to the overflow menu. */ void handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y); // finds a control under the specified LOCAL point LLUICtrl* findChildByLocalCoords(S32 x, S32 y); + bool findDragAndDropTarget(LLUUID &target_id, bool &insert_before, S32 x, S32 y); + // checks if the current order of the favorites items must be saved BOOL needToSaveItemsOrder(const LLInventoryModel::item_array_t& items); @@ -145,27 +146,25 @@ private: void createOverflowMenu(); - void updateMenuItems(LLToggleableMenu* menu); + void updateOverflowMenuItems(); // Fits menu item label width with favorites menu width void fitLabelWidth(LLMenuItemCallGL* menu_item); void addOpenLandmarksMenuItem(LLToggleableMenu* menu); - void positionAndShowMenu(LLToggleableMenu* menu); + void positionAndShowOverflowMenu(); - BOOL mShowDragMarker; + bool mShowDragMarker; LLUICtrl* mLandingTab; LLUICtrl* mLastTab; LLTextBox* mMoreTextBox; LLTextBox* mBarLabel; LLUUID mDragItemId; - BOOL mStartDrag; + bool mStartDrag; LLInventoryModel::item_array_t mItems; - BOOL mTabsHighlightEnabled; - S32 mMouseX; S32 mMouseY;