diff options
| -rw-r--r-- | indra/llimage/llimagebmp.cpp | 6 | ||||
| -rw-r--r-- | indra/llimage/llimagedxt.cpp | 6 | ||||
| -rw-r--r-- | indra/llimage/llimagejpeg.cpp | 6 | ||||
| -rw-r--r-- | indra/llimagej2coj/llimagej2coj.cpp | 6 | ||||
| -rw-r--r-- | indra/llkdu/llimagej2ckdu.cpp | 6 | ||||
| -rw-r--r-- | indra/newview/llfloaterimagepreview.cpp | 16 | ||||
| -rw-r--r-- | indra/newview/llfloatermodelpreview.cpp | 86 | ||||
| -rw-r--r-- | indra/newview/llfloatermodelpreview.h | 3 | ||||
| -rw-r--r-- | indra/newview/llmeshrepository.cpp | 15 | ||||
| -rw-r--r-- | indra/newview/llmeshrepository.h | 8 | ||||
| -rw-r--r-- | indra/newview/llviewerstats.cpp | 30 | ||||
| -rw-r--r-- | indra/newview/llviewerstats.h | 9 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_stats.xml | 8 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/notifications.xml | 8 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/strings.xml | 1 | 
15 files changed, 206 insertions, 8 deletions
diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp index 2a328675c2..c8f99380ea 100644 --- a/indra/llimage/llimagebmp.cpp +++ b/indra/llimage/llimagebmp.cpp @@ -558,6 +558,12 @@ bool LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time)          LL_INFOS() << "Dropping alpha information during BMP encoding" << LL_ENDL;      } +    if (raw_image->isBufferInvalid()) +    { +        setLastError("Invalid input, no buffer"); +        return false; +    } +      setSize(raw_image->getWidth(), raw_image->getHeight(), dst_components);      U8 magic[14]; diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 6b960f9077..c3fd0c5aa8 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -329,6 +329,12 @@ bool LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_  {      llassert_always(raw_image); +    if (raw_image->isBufferInvalid()) +    { +        setLastError("Invalid input, no buffer"); +        return false; +    } +      S32 ncomponents = raw_image->getComponents();      EFileFormat format;      switch (ncomponents) diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp index dd3efb3459..71b139bc82 100644 --- a/indra/llimage/llimagejpeg.cpp +++ b/indra/llimage/llimagejpeg.cpp @@ -497,6 +497,12 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )      resetLastError(); +    if (raw_image->isBufferInvalid()) +    { +        setLastError("Invalid input, no buffer"); +        return false; +    } +      LLImageDataSharedLock lockIn(raw_image);      LLImageDataLock lockOut(this); diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index 717b0a6e86..6ebbe359b9 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -897,6 +897,12 @@ bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod  bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, bool reversible)  { +    if (raw_image.isBufferInvalid()) +    { +        base.setLastError("Invalid input, no buffer"); +        return false; +    } +      JPEG2KEncode encode(comment_text, reversible);      bool encoded = encode.encode(raw_image, base);      if (!encoded) diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 0d1f2b3006..b824fd8385 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -662,6 +662,12 @@ bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co      bool vflip = true;      bool hflip = false; +    if (raw_image.isBufferInvalid()) +    { +        base.setLastError("Invalid input, no buffer"); +        return false; +    } +      try      {          // Set up input image files diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 42a5df5d17..550c3adc27 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -288,7 +288,9 @@ void LLFloaterImagePreview::onBtnOK()          }          else          { -            LLNotificationsUtil::add("ErrorEncodingImage"); +            LLSD args; +            args["REASON"] = LLImage::getLastThreadError(); +            LLNotificationsUtil::add("ErrorEncodingImage", args);              LL_WARNS() << "Error encoding image" << LL_ENDL;          }      } @@ -423,6 +425,18 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename)          return false;      } +    // raw image is limited to 256MB so need at least some upper limit that fits into that +    constexpr S32 MAX_IMAGE_AREA = 8096 * 8096; + +    if (image_info.getWidth() * image_info.getHeight() > MAX_IMAGE_AREA) +    { +        LLStringUtil::format_map_t args; +        args["PIXELS"] = llformat("%dM", (S32)(MAX_IMAGE_AREA / 1000000)); + +        mImageLoadError = LLTrans::getString("texture_load_area_error", args); +        return false; +    } +      // Load the image      LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);      if (image.isNull()) diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6a6766fb3f..08d3488ef2 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -503,7 +503,10 @@ void LLFloaterModelPreview::onClickCalculateBtn()      mUploadModelUrl.clear();      mModelPhysicsFee.clear(); -    gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, +    lod_sources_map_t lod_sources; +    fillLODSourceStatistics(lod_sources); + +    gMeshRepo.uploadModel(mModelPreview->mUploadData, lod_sources, mModelPreview->mPreviewScale,                            childGetValue("upload_textures").asBoolean(),                            upload_skinweights, upload_joint_positions, lock_scale_if_joint_position,                            mUploadModelUrl, mDestinationFolderId, false, @@ -1317,8 +1320,84 @@ void LLFloaterModelPreview::createSmoothComboBox(LLComboBox* combo_box, float mi          std::string label = (++ilabel == SMOOTH_VALUES_NUMBER) ? "10 (max)" : llformat("%.1d", ilabel);          combo_box->add(label, value, ADD_BOTTOM, true);      } +} + +std::string get_source_file_extr(const std::string& filename) +{ +    if (std::string::npos != filename.rfind(".gltf") +        || std::string::npos != filename.rfind(".glb")) +    { +        return "gltf"; +    } +    else if (std::string::npos != filename.rfind(".dae")) +    { +        return "dae"; +    } +    else if (std::string::npos != filename.rfind(".slm")) +    { +        return "slm"; +    } +    else +    { +        return "unknown file"; +    } +} +void LLFloaterModelPreview::fillLODSourceStatistics(LLFloaterModelPreview::lod_sources_map_t& lod_sources) const +{ +    lod_sources.clear(); +    // This doesn't nessesarily reflect the actual source of meshes, just user choices, +    // some meshes could have been matched from different lods, but should be good +    // enough for statistics. +    for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) +    { +        const std::string &lod_string = lod_name[lod]; +        if (mLODMode[lod] == LLModelPreview::USE_LOD_ABOVE) +        { +            lod_sources[lod_string] = "lod above"; +        } +        else if (mLODMode[lod] == LLModelPreview::MESH_OPTIMIZER_AUTO +            || mLODMode[lod] == LLModelPreview::MESH_OPTIMIZER_PRECISE +            || mLODMode[lod] == LLModelPreview::MESH_OPTIMIZER_SLOPPY) +        { +            lod_sources[lod_string] = "generated"; +        } +        else if (mLODMode[lod] == LLModelPreview::LOD_FROM_FILE) +        { +            const std::string& file = mModelPreview->mLODFile[lod]; +            lod_sources[lod_string] = get_source_file_extr(file); +        } +        else +        { +            lod_sources[lod_string] = "unknown source"; +        } +    } +    if (mModelPreview->mLODFile[LLModel::LOD_PHYSICS].empty()) +    { +        if (mModelPreview->mPhysicsSearchLOD >= 0 && mModelPreview->mPhysicsSearchLOD <= 3) +        { +            lod_sources["physics"] = lod_name[mModelPreview->mPhysicsSearchLOD]; +        } +        else +        { +            lod_sources["physics"] = "none"; +        } +    } +    else +    { +        const std::string& file = mModelPreview->mLODFile[LLModel::LOD_PHYSICS]; +        if (std::string::npos == file.rfind("cube.dae")) +        { +            // There is a chance it will misfire if someone tries to upload a cube.dae mesh, +            // but should be negligible enough. +            lod_sources["physics"] = get_source_file_extr(file); +        } +        else +        { +            lod_sources["physics"] = "bounding box"; +        } +    }  }  //----------------------------------------------------------------------------- @@ -1656,7 +1735,10 @@ void LLFloaterModelPreview::onUpload(void* user_data)          mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions, lock_scale_if_joint_position);      } -    gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, +    lod_sources_map_t lod_sources; +    mp->fillLODSourceStatistics(lod_sources); + +    gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, lod_sources, mp->mModelPreview->mPreviewScale,                            mp->childGetValue("upload_textures").asBoolean(),                            upload_skinweights, upload_joint_positions, lock_scale_if_joint_position,                            mp->mUploadModelUrl, mp->mDestinationFolderId, diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 7b652a3613..982f36c46e 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -223,6 +223,9 @@ private:      void createSmoothComboBox(LLComboBox* combo_box, float min, float max); +    typedef std::map<std::string, std::string> lod_sources_map_t; +    void fillLODSourceStatistics(lod_sources_map_t& lod_sources) const; +      LLUUID mDestinationFolderId;      LLButton* mUploadBtn;      LLButton* mCalculateBtn; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 07d68fc3ec..fd3360b234 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2569,7 +2569,8 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_      return MESH_OK;  } -LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures, +LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, const LLMeshUploadThread::lod_sources_map_t& sources_list, +                                       LLVector3& scale, bool upload_textures,                                         bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,                                         const std::string & upload_url, LLUUID destination_folder_id, bool do_upload,                                         LLHandle<LLWholeModelFeeObserver> fee_observer, @@ -2584,6 +2585,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,      mUploadObserverHandle(upload_observer)  {      mInstanceList = data; +    mLodSources = sources_list;      mUploadTextures = upload_textures;      mUploadSkin = upload_skin;      mUploadJoints = upload_joints; @@ -2721,6 +2723,12 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, std::vector<std::string>&      res["mesh_list"] = LLSD::emptyArray();      res["texture_list"] = LLSD::emptyArray();      res["instance_list"] = LLSD::emptyArray(); +    LLSD& lod_sources = res["source_format"]; +    lod_sources["high"] = 0; +    for (auto &source : mLodSources) +    { +        lod_sources[source.first] = source.second; +    }      S32 mesh_num = 0;      S32 texture_num = 0; @@ -5026,12 +5034,13 @@ bool LLMeshRepoThread::hasHeader(const LLUUID& mesh_id) const      return iter != mMeshHeader.end();  } -void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures, +void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, const std::map<std::string, std::string> &lod_sources, +                                   LLVector3& scale, bool upload_textures,                                     bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,                                     std::string upload_url, const LLUUID& destination_folder_id, bool do_upload,                                     LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer)  { -    LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, +    LLMeshUploadThread* thread = new LLMeshUploadThread(data, lod_sources, scale, upload_textures,                                                          upload_skin, upload_joints, lock_scale_if_joint_position,                                                          upload_url, destination_folder_id, do_upload, fee_observer, upload_observer);      mUploadWaitList.push_back(thread); diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 2b772f7803..ab17b921d6 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -691,6 +691,8 @@ public:      };      typedef std::map<LLPointer<LLModel>, instance_list, LLUploadModelInstanceLess> instance_map;      instance_map    mInstance; +    typedef std::map<std::string, std::string> lod_sources_map_t; +    lod_sources_map_t mLodSources;      LLMutex*        mMutex;      S32             mPendingUploads; @@ -707,7 +709,8 @@ public:      std::string     mWholeModelUploadURL;      LLUUID          mDestinationFolderId; -    LLMeshUploadThread(instance_list& data, LLVector3& scale, bool upload_textures, +    LLMeshUploadThread(instance_list& data, const lod_sources_map_t& sources_list, +                       LLVector3& scale, bool upload_textures,                         bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,                         const std::string & upload_url,                         const LLUUID destination_folder_id = LLUUID::null, @@ -869,7 +872,8 @@ public:      bool meshUploadEnabled();      bool meshRezEnabled(); -    void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures, +    void uploadModel(std::vector<LLModelInstance>& data, const std::map<std::string, std::string> &lod_sources, +                     LLVector3& scale, bool upload_textures,                       bool upload_skin, bool upload_joints, bool lock_scale_if_joint_position,                       std::string upload_url,                       const LLUUID& destination_folder_id = LLUUID::null, diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index cf0cf2a6a9..59bb78f8f4 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -234,6 +234,8 @@ LLTrace::SampleStatHandle<U32> FRAMETIME_JITTER_EVENTS("frametimeevents", "Numbe                                  FRAMETIME_JITTER_EVENTS_LAST_MINUTE("frametimeeventslastmin", "Number of frametime events in the last minute.");  LLTrace::SampleStatHandle<F64> NOTRMALIZED_FRAMETIME_JITTER_SESSION("normalizedframetimejitter", "Normalized frametime jitter over the session."); +LLTrace::SampleStatHandle<F64> NFTV("nftv", "Normalized frametime variation."); +LLTrace::SampleStatHandle<F64> NORMALIZED_FRAMTIME_JITTER_PERIOD("normalizedframetimejitterperiod", "Normalized frametime jitter over the last 5 seconds.");  LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP("agentpositionsnap", "agent position corrections"); @@ -322,6 +324,8 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff)          sample(LLStatViewer::FRAMETIME_JITTER_CUMULATIVE, mTotalFrametimeJitter);          sample(LLStatViewer::NOTRMALIZED_FRAMETIME_JITTER_SESSION, mTotalFrametimeJitter / mTotalTime); +        mLastNoramlizedSessionJitter = mTotalFrametimeJitter / mTotalTime; +          static LLCachedControl<F32> frameTimeEventThreshold(gSavedSettings, "StatsFrametimeEventThreshold", 0.1f);          if (time_diff - mLastTimeDiff > mLastTimeDiff * frameTimeEventThreshold()) @@ -360,6 +364,27 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff)              sample(LLStatViewer::FRAMETIME_JITTER_99TH, ninety_ninth_percentile);              sample(LLStatViewer::FRAMETIME_JITTER_95TH, ninety_fifth_percentile); +            F64 averageFrameTime = 0; +            for (const auto& frame_time : mFrameTimes) +            { +                averageFrameTime += frame_time.value(); +            } +            averageFrameTime /= mFrameTimes.size(); + +            sample(LLStatViewer::NFTV, frame_time_stddev / averageFrameTime); +            mLastNormalizedFrametimeVariance = frame_time_stddev / averageFrameTime; + +            // Add up all of the jitter values. +            F64 totalJitter = 0; +            for (const auto& frame_jitter : mFrameTimesJitter) +            { +                totalJitter += frame_jitter.value(); +            } + +            mLastNormalizedPeriodJitter = totalJitter / mLastFrameTimeSample; + +            sample(LLStatViewer::NORMALIZED_FRAMTIME_JITTER_PERIOD, mLastNormalizedPeriodJitter); +              mFrameTimes.clear();              mFrameTimesJitter.clear();              mLastFrameTimeSample = F64Seconds(0); @@ -648,6 +673,11 @@ void send_viewer_stats(bool include_preferences)      // send fps only for time app spends in foreground      agent["fps"] = (F32)gForegroundFrameCount / gForegroundTime.getElapsedTimeF32(); + +    agent["normalized_session_jitter"] = LLViewerStats::instance().getLastNormalizedSessionJitter(); +    agent["normalized_frametime_variance"] = LLViewerStats::instance().getLastNormalizedFrametimeVariance(); +    agent["normalized_period_jitter"]      = LLViewerStats::instance().getLastNormalizedPeriodJitter(); +      agent["version"] = LLVersionInfo::instance().getChannelAndVersion();      std::string language = LLUI::getLanguage();      agent["language"] = language; diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 63fb7d4a17..011269d7ee 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -271,6 +271,10 @@ public:      LLTrace::Recording& getRecording() { return mRecording; }      const LLTrace::Recording& getRecording() const { return mRecording; } +    F64 getLastNormalizedSessionJitter() const { return mLastNoramlizedSessionJitter; } +    F64 getLastNormalizedFrametimeVariance() const { return mLastNormalizedFrametimeVariance; } +    F64 getLastNormalizedPeriodJitter() const { return mLastNormalizedPeriodJitter; } +  private:      LLTrace::Recording              mRecording; @@ -286,6 +290,11 @@ private:      F64Seconds              mTimeSinceLastEventSample;      std::vector<F64Seconds>      mFrameTimes;          // used for frame time stats      std::vector<F64Seconds> mFrameTimesJitter;    // used for frame time jitter stats + +    F64 mLastNoramlizedSessionJitter; // used for frame time jitter stats +    F64 mLastNormalizedFrametimeVariance; // Used when submitting jitter stats +    F64 mLastNormalizedPeriodJitter; +  };  static const F32 SEND_STATS_PERIOD = 300.0f; diff --git a/indra/newview/skins/default/xui/en/floater_stats.xml b/indra/newview/skins/default/xui/en/floater_stats.xml index f2309eb817..1600c422c3 100644 --- a/indra/newview/skins/default/xui/en/floater_stats.xml +++ b/indra/newview/skins/default/xui/en/floater_stats.xml @@ -58,6 +58,14 @@                      label="normalized sess. jitter"                      decimal_digits="4"                      stat="normalizedframetimejitter"/> +          <stat_bar name="normalized_period_jitter" +                    label="normalized period jitter" +                    decimal_digits="4" +                    stat="normalizedframetimejitterperiod"/> +          <stat_bar name="normalized_frametime_variation" +                    label="normalized frametime variation" +                    decimal_digits="4" +                    stat="nftv"/>            <stat_bar name="frame_events_per_minute"                      label="frame events/minute"                      decimal_digits="2" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 10c9efffd1..9963ccd84b 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -1322,6 +1322,14 @@ Error encoding snapshot.    <notification     icon="alertmodal.tga" +   name="ErrorEncodingImage" +   type="alertmodal"> +    Failed to encode image, reason: [REASON] +    <tag>fail</tag> +  </notification> +   +  <notification +   icon="alertmodal.tga"     name="ErrorTextureCannotAfford"     type="alertmodal">      You need L$[COST] to save a texture to your inventory. You may either buy L$ or save the photo to your computer instead. diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index ccae7d3df1..25827fa236 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3971,6 +3971,7 @@ Abuse Report</string>    <string name="AvatarBirthDateFormatShort">[mthnum,datetime,slt]/[day,datetime,slt]</string>    <string name="DefaultMimeType">none/none</string> +  <string name="texture_load_area_error">Can't load images larger than [PIXELS] pixels</string>    <string name="texture_load_dimensions_error">Can't load images larger than [WIDTH]*[HEIGHT]</string>    <string name="texture_load_format_error">Incorrect image format.</string>    <string name="texture_load_empty_file">File is empty.</string>  | 
