diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index f80c1a15e..fc7b0a878 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -30,8 +30,6 @@ include(BuildVersion) include(UnixInstall) -set (DISABLE_FATAL_WARNINGS CACHE BOOL TRUE) - if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type. One of: Debug Release RelWithDebInfo" FORCE) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 319c9c13c..449186a08 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -270,10 +270,10 @@ endif (DARWIN) if (LINUX OR DARWIN) if(${CMAKE_C_COMPILER} MATCHES "gcc*") - set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs") + set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs") set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual") elseif(${CMAKE_C_COMPILER} MATCHES "clang*") - set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-tautological-compare -Wno-char-subscripts -Wno-gnu -Wno-logical-op-parentheses -Wno-non-virtual-dtor ") + set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-tautological-compare -Wno-char-subscripts -Wno-gnu -Wno-logical-op-parentheses -Wno-non-virtual-dtor") set(UNIX_WARNINGS "${UNIX_WARNINGS} -Woverloaded-virtual -Wno-parentheses-equality -Wno-reorder -Wno-unused-function -Wno-unused-value -Wno-unused-variable") set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS}") elseif(${CMAKE_C_COMPILER} MATCHES "icc") @@ -281,8 +281,11 @@ if (LINUX OR DARWIN) set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS}") endif() + # Use -DDISABLE_FATAL_WARNINGS:BOOL=FALSE during configuration to enable fatal warnings. + set(DISABLE_FATAL_WARNINGS TRUE CACHE BOOL "Set this to FALSE to enable fatal warnings.") if (NOT DISABLE_FATAL_WARNINGS) set(UNIX_WARNINGS "${UNIX_WARNINGS} -Werror") + set(UNIX_CXX_WARNINGS "${UNIX_CXX_WARNINGS} -Werror") endif (NOT DISABLE_FATAL_WARNINGS) set(CMAKE_C_FLAGS "${UNIX_WARNINGS} ${CMAKE_C_FLAGS}") diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 105b69d34..9f49fcbf5 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -203,7 +203,6 @@ inline T* get_ptr_in_map(const std::map& inmap, const K& key) template inline bool is_in_map(const std::map& inmap, const K& key) { - typedef typename std::map::const_iterator map_iter; if(inmap.find(key) == inmap.end()) { return false; diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index eb45729b9..53e890040 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -22,6 +22,7 @@ include_directories( ) set(llmessage_SOURCE_FILES + aiaverage.cpp aicurl.cpp aicurleasyrequeststatemachine.cpp aicurlperservice.cpp @@ -109,6 +110,7 @@ set(llmessage_SOURCE_FILES set(llmessage_HEADER_FILES CMakeLists.txt + aiaverage.h aicurl.h aicurleasyrequeststatemachine.h aicurlperservice.h diff --git a/indra/llmessage/aiaverage.cpp b/indra/llmessage/aiaverage.cpp new file mode 100644 index 000000000..10aafd852 --- /dev/null +++ b/indra/llmessage/aiaverage.cpp @@ -0,0 +1,81 @@ +/** + * @file aiaverage.cpp + * @brief Implementation of AIAverage + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 11/04/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#include "sys.h" +#include "aiaverage.h" +#include "llerror.h" // llassert + +void AIAverage::cleanup(U64 clock_tick) +{ + // This expression can fail because the curl thread caches the time in + // sTime_10ms for the duration of an entire loop. Therefore, the time can + // go into the next 40ms and a texture fetch worker thread might call + // cleanup() with that time, setting mCurrentClock to a value (one) + // larger than sTime_10ms / 4. Next, the curl thread can continue to call + // this function with the smaller value; in that case just add the new + // data to the current bucket. + // + // Or, this is just the one-time initialization that happens the first + // time this is called. In that case initialize just mCurrentClock: + // the rest is already initialized upon construction. + if (LL_LIKELY(clock_tick > mCurrentClock)) + { + // Advance to the next bucket. + ++mCurrentBucket; + mCurrentBucket %= mNrOfBuckets; + // Initialize the new bucket. + mData[mCurrentBucket].time = clock_tick; + // Clean up old buckets. + U64 old_time = clock_tick - mNrOfBuckets; + if (LL_UNLIKELY(mTail == mCurrentBucket) || // Extremely unlikely: only happens when data was added EVERY clock tick for the past mNrOfBuckets clock ticks. + mData[mTail].time <= old_time) + { + do + { + mSum -= mData[mTail].sum; + mN -= mData[mTail].n; + mData[mTail].sum = 0; + mData[mTail].n = 0; + ++mTail; + if (LL_UNLIKELY(mTail == mNrOfBuckets)) + { + mTail = 0; + } + } + while (mData[mTail].time <= old_time); + } + // This was set to zero when mTail passed this point (likely not this call, but a few calls ago). + llassert(mData[mCurrentBucket].sum == 0 && + mData[mCurrentBucket].n == 0); + } + mCurrentClock = clock_tick; + return; +} + diff --git a/indra/llmessage/aiaverage.h b/indra/llmessage/aiaverage.h new file mode 100644 index 000000000..f8f344df6 --- /dev/null +++ b/indra/llmessage/aiaverage.h @@ -0,0 +1,108 @@ +/** + * @file aiaverage.h + * @brief Definition of class AIAverage + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 11/04/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AIAVERAGE_H +#define AIAVERAGE_H + +#include "llpreprocessor.h" +#include "stdtypes.h" // U32, U64 +#include "llthread.h" // LLMutex +#include // size_t +#include + +class AIAverage { + private: + struct Data { + U32 sum; // Accumulated sum of the 'n' passed to operator()(size_t n, U64 clock_tick) with clock_tick == time. + U32 n; // The number of calls to operator(). + U64 time; // The clock_tick as passed to operator()(size_t n, U64 clock_tick) that sum corresponds to. + }; + + U64 mCurrentClock; // The current (last) time that operator() was called with, or -1 when not initialized. + int mTail; // The oldest bucket with still valid data. + int mCurrentBucket; // The bucket that corresponds to mCurrentClock. + size_t mSum; // The sum of all the 'n' passed to operator()(size_t n, U64 clock_tick) for all passed mNrOfBuckets time units. + U32 mN; // The number of calls to operator(). + int const mNrOfBuckets; // Size of mData. + std::vector mData; // The buckets. + LLMutex mLock; // Mutex for all of the above data. + + public: + AIAverage(int number_of_buckets) : mCurrentClock(~(U64)0), mTail(0), mCurrentBucket(0), mSum(0), mN(0), mNrOfBuckets(number_of_buckets), mData(number_of_buckets) + { + // Fill mData with all zeroes (much faster than adding a constructor to Data). + std::memset(&*mData.begin(), 0, number_of_buckets * sizeof(Data)); + } + size_t addData(U32 n, U64 clock_tick) + { + DoutEntering(dc::curl, "AIAverage::addData(" << n << ", " << clock_tick << ")"); + mLock.lock(); + if (LL_UNLIKELY(clock_tick != mCurrentClock)) + { + cleanup(clock_tick); + } + mSum += n; + mN += 1; + mData[mCurrentBucket].sum += n; + mData[mCurrentBucket].n += 1; + size_t sum = mSum; + mLock.unlock(); + Dout(dc::curl, "Current sum: " << sum << ", average: " << (sum / mN)); + return sum; + } + size_t truncateData(U64 clock_tick) + { + mLock.lock(); + if (clock_tick != mCurrentClock) + { + cleanup(clock_tick); + } + size_t sum = mSum; + mLock.unlock(); + return sum; + } + double getAverage(double avg_no_data) + { + mLock.lock(); + double avg = mSum; + llassert(mN != 0 || mSum == 0); + if (LL_UNLIKELY(mN == 0)) + avg = avg_no_data; + else + avg /= mN; + mLock.unlock(); + return avg; + } + + private: + void cleanup(U64 clock_tick); +}; + +#endif // AIAVERAGE diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index 651e0e9eb..93153951a 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -1267,8 +1267,9 @@ static int const HTTP_REDIRECTS_DEFAULT = 10; LLChannelDescriptors const BufferedCurlEasyRequest::sChannels; LLMutex BufferedCurlEasyRequest::sResponderCallbackMutex; bool BufferedCurlEasyRequest::sShuttingDown = false; +AIAverage BufferedCurlEasyRequest::sHTTPBandwidth(25); -BufferedCurlEasyRequest::BufferedCurlEasyRequest() : mRequestTransferedBytes(0), mResponseTransferedBytes(0), mBufferEventsTarget(NULL), mStatus(HTTP_INTERNAL_ERROR_OTHER) +BufferedCurlEasyRequest::BufferedCurlEasyRequest() : mRequestTransferedBytes(0), mTotalRawBytes(0), mBufferEventsTarget(NULL), mStatus(HTTP_INTERNAL_ERROR_OTHER) { AICurlInterface::Stats::BufferedCurlEasyRequest_count++; } @@ -1332,7 +1333,7 @@ void BufferedCurlEasyRequest::resetState(void) mOutput.reset(); mInput.reset(); mRequestTransferedBytes = 0; - mResponseTransferedBytes = 0; + mTotalRawBytes = 0; mBufferEventsTarget = NULL; mStatus = HTTP_INTERNAL_ERROR_OTHER; } diff --git a/indra/llmessage/aicurlperservice.h b/indra/llmessage/aicurlperservice.h index cf4d8ba71..8cd310f40 100644 --- a/indra/llmessage/aicurlperservice.h +++ b/indra/llmessage/aicurlperservice.h @@ -45,6 +45,7 @@ #include #include #include "aithreadsafe.h" +#include "aiaverage.h" class AICurlEasyRequest; class AIPerServiceRequestQueue; @@ -89,7 +90,7 @@ class AIPerServiceRequestQueue { static threadsafe_instance_map_type sInstanceMap; // Map of AIPerServiceRequestQueue instances with the hostname as key. friend class AIThreadSafeSimpleDC; //threadsafe_PerServiceRequestQueue - AIPerServiceRequestQueue(void) : mQueuedCommands(0), mAdded(0), mQueueEmpty(false), mQueueFull(false), mRequestStarvation(false) { } + AIPerServiceRequestQueue(void) : mQueuedCommands(0), mAdded(0), mQueueEmpty(false), mQueueFull(false), mRequestStarvation(false), mHTTPBandwidth(25) { } // 25 = 1000 ms / 40 ms. public: typedef instance_map_type::iterator iterator; @@ -124,6 +125,8 @@ class AIPerServiceRequestQueue { static bool sQueueFull; // Set to true when sTotalQueued is still larger than zero after popping any queue. static bool sRequestStarvation; // Set to true when any queue was about to be popped when sTotalQueued was already zero. + AIAverage mHTTPBandwidth; // Keeps track on number of bytes received for this service in the past second. + public: void added_to_command_queue(void) { ++mQueuedCommands; } void removed_from_command_queue(void) { --mQueuedCommands; llassert(mQueuedCommands >= 0); } @@ -141,14 +144,17 @@ class AIPerServiceRequestQueue { S32 pipelined_requests(void) const { return mQueuedCommands + mQueuedRequests.size() + mAdded; } static S32 total_queued_size(void) { return sTotalQueued; } + AIAverage& bandwidth(void) { return mHTTPBandwidth; } + AIAverage const& bandwidth(void) const { return mHTTPBandwidth; } + // Returns true if curl can handle another request for this host. // Should return false if the maximum allowed HTTP bandwidth is reached, or when // the latency between request and actual delivery becomes too large. - static bool wantsMoreHTTPRequestsFor(AIPerServiceRequestQueuePtr const& per_service, bool too_much_bandwidth); + static bool wantsMoreHTTPRequestsFor(AIPerServiceRequestQueuePtr const& per_service, F32 max_kbps, bool no_bandwidth_throttling); private: // Disallow copying. - AIPerServiceRequestQueue(AIPerServiceRequestQueue const&) { } + AIPerServiceRequestQueue(AIPerServiceRequestQueue const&) : mHTTPBandwidth(0) { } }; namespace AICurlPrivate { diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index d0fa202ca..5558e31a4 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -396,6 +396,9 @@ class BufferedCurlEasyRequest : public CurlEasyRequest { // Post-initialization, set the parent to pass the events to. void send_buffer_events_to(AIBufferedCurlEasyRequestEvents* target) { mBufferEventsTarget = target; } + // Called whenever new body data was (might be) received. Keeps track of the used HTTP bandwidth. + void update_body_bandwidth(void); + protected: // Events from this class. /*virtual*/ void received_HTTP_header(void); @@ -411,13 +414,14 @@ class BufferedCurlEasyRequest : public CurlEasyRequest { U32 mStatus; // HTTP status, decoded from the first header line. std::string mReason; // The "reason" from the same header line. U32 mRequestTransferedBytes; - U32 mResponseTransferedBytes; + size_t mTotalRawBytes; // Raw body data (still, possibly, compressed) received from the server so far. AIBufferedCurlEasyRequestEvents* mBufferEventsTarget; public: static LLChannelDescriptors const sChannels; // Channel object for mInput (channel out()) and mOutput (channel in()). static LLMutex sResponderCallbackMutex; // Locked while calling back any overridden ResponderBase::finished and/or accessing sShuttingDown. static bool sShuttingDown; // If true, no additional calls to ResponderBase::finished will be made anymore. + static AIAverage sHTTPBandwidth; // HTTP bandwidth usage of all services combined. private: // This class may only be created by constructing a ThreadSafeBufferedCurlEasyRequest. diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index a586ece81..a7b0e4642 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -33,6 +33,7 @@ #include "aihttptimeoutpolicy.h" #include "aihttptimeout.h" #include "aicurlperservice.h" +#include "aiaverage.h" #include "lltimer.h" // ms_sleep, get_clock_count #include "llhttpstatuscodes.h" #include "llbuffer.h" @@ -1829,6 +1830,8 @@ void MultiHandle::check_msg_queue(void) void MultiHandle::finish_easy_request(AICurlEasyRequest const& easy_request, CURLcode result) { AICurlEasyRequest_wat curl_easy_request_w(*easy_request); + // Final body bandwidth update. + curl_easy_request_w->update_body_bandwidth(); // Store the result in the easy handle. curl_easy_request_w->storeResult(result); #ifdef CWDEBUG @@ -2023,10 +2026,10 @@ void BufferedCurlEasyRequest::processOutput(void) if (responseCode == HTTP_INTERNAL_ERROR_LOW_SPEED) { // Rewrite error to something understandable. - responseReason = llformat("Connection to \"%s\" stalled: download speed dropped below %u bytes/s for %u seconds (up till that point, %s received a total of %u bytes). " + responseReason = llformat("Connection to \"%s\" stalled: download speed dropped below %u bytes/s for %u seconds (up till that point, %s received a total of %lu bytes). " "To change these values, go to Advanced --> Debug Settings and change CurlTimeoutLowSpeedLimit and CurlTimeoutLowSpeedTime respectively.", mResponder->getURL().c_str(), mResponder->getHTTPTimeoutPolicy().getLowSpeedLimit(), mResponder->getHTTPTimeoutPolicy().getLowSpeedTime(), - mResponder->getName(), mResponseTransferedBytes); + mResponder->getName(), mTotalRawBytes); } setopt(CURLOPT_FRESH_CONNECT, TRUE); } @@ -2093,7 +2096,9 @@ size_t BufferedCurlEasyRequest::curlWriteCallback(char* data, size_t size, size_ // BufferedCurlEasyRequest::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite. //S32 bytes = llmin(size * nmemb, buffer_w->mBodyLimit); buffer_w->mBodyLimit -= bytes; self_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes); - self_w->mResponseTransferedBytes += bytes; // Accumulate data received from the server. + // Update HTTP bandwith. + self_w->update_body_bandwidth(); + // Update timeout administration. if (self_w->httptimeout()->data_received(bytes)) // Update timeout administration. { // Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR. @@ -2102,6 +2107,25 @@ size_t BufferedCurlEasyRequest::curlWriteCallback(char* data, size_t size, size_ return bytes; } +void BufferedCurlEasyRequest::update_body_bandwidth(void) +{ + double size_download; // Total amount of raw bytes received so far (ie. still compressed, 'bytes' is uncompressed). + getinfo(CURLINFO_SIZE_DOWNLOAD, &size_download); + size_t total_raw_bytes = size_download; + size_t raw_bytes = total_raw_bytes - mTotalRawBytes; + mTotalRawBytes = total_raw_bytes; + // Note that in some cases (like HTTP_PARTIAL_CONTENT), the output of CURLINFO_SIZE_DOWNLOAD lags + // behind and will return 0 the first time, and the value of the previous chunk the next time. + // The last call from MultiHandle::finish_easy_request recorrects this, in that case. + if (raw_bytes > 0) + { + U64 const sTime_40ms = curlthread::HTTPTimeout::sTime_10ms >> 2; + AIAverage& http_bandwidth(PerServiceRequestQueue_wat(*getPerServicePtr())->bandwidth()); + http_bandwidth.addData(raw_bytes, sTime_40ms); + sHTTPBandwidth.addData(raw_bytes, sTime_40ms); + } +} + //static size_t BufferedCurlEasyRequest::curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data) { @@ -2189,6 +2213,11 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size self_w->httptimeout()->being_redirected(); } } + // Update HTTP bandwidth. + U64 const sTime_40ms = curlthread::HTTPTimeout::sTime_10ms >> 2; + AIAverage& http_bandwidth(PerServiceRequestQueue_wat(*self_w->getPerServicePtr())->bandwidth()); + http_bandwidth.addData(header_len, sTime_40ms); + sHTTPBandwidth.addData(header_len, sTime_40ms); // Update timeout administration. This must be done after the status is already known. if (self_w->httptimeout()->data_received(header_len/*,*/ ASSERT_ONLY_COMMA(self_w->upload_error_status()))) { @@ -2533,6 +2562,14 @@ U32 getNumHTTPAdded(void) return AICurlPrivate::curlthread::MultiHandle::total_added_size(); } +size_t getHTTPBandwidth(void) +{ + using namespace AICurlPrivate; + + U64 const sTime_40ms = get_clock_count() * curlthread::HTTPTimeout::sClockWidth_40ms; + return BufferedCurlEasyRequest::sHTTPBandwidth.truncateData(sTime_40ms); +} + } // namespace AICurlInterface // Return true if we want at least one more HTTP request for this host. @@ -2560,7 +2597,7 @@ U32 getNumHTTPAdded(void) // running requests (in MultiHandle::mAddedEasyRequests)). // //static -bool AIPerServiceRequestQueue::wantsMoreHTTPRequestsFor(AIPerServiceRequestQueuePtr const& per_service, bool too_much_bandwidth) +bool AIPerServiceRequestQueue::wantsMoreHTTPRequestsFor(AIPerServiceRequestQueuePtr const& per_service, F32 max_kbps, bool no_bandwidth_throttling) { using namespace AICurlPrivate; using namespace AICurlPrivate::curlthread; @@ -2587,17 +2624,21 @@ bool AIPerServiceRequestQueue::wantsMoreHTTPRequestsFor(AIPerServiceRequestQueue // Check if it's ok to get a new request for this particular host and update the per-host threshold. + AIAverage* http_bandwidth_ptr; + // Atomic read max_pipelined_requests_per_service for the below calculations. S32 const max_pipelined_requests_per_service_cache = max_pipelined_requests_per_service; { - PerServiceRequestQueue_rat per_service_r(*per_service); - S32 const pipelined_requests_per_service = per_service_r->pipelined_requests(); + PerServiceRequestQueue_wat per_service_w(*per_service); + S32 const pipelined_requests_per_service = per_service_w->pipelined_requests(); reject = pipelined_requests_per_service >= max_pipelined_requests_per_service_cache; equal = pipelined_requests_per_service == max_pipelined_requests_per_service_cache; - increment_threshold = per_service_r->mRequestStarvation; - decrement_threshold = per_service_r->mQueueFull && !per_service_r->mQueueEmpty; + increment_threshold = per_service_w->mRequestStarvation; + decrement_threshold = per_service_w->mQueueFull && !per_service_w->mQueueEmpty; // Reset flags. - per_service_r->mQueueFull = per_service_r->mQueueEmpty = per_service_r->mRequestStarvation = false; + per_service_w->mQueueFull = per_service_w->mQueueEmpty = per_service_w->mRequestStarvation = false; + // Grab per service bandwidth object. + http_bandwidth_ptr = &per_service_w->bandwidth(); } if (decrement_threshold) { @@ -2621,10 +2662,69 @@ bool AIPerServiceRequestQueue::wantsMoreHTTPRequestsFor(AIPerServiceRequestQueue return false; } - //AIFIXME: better bandwidth check here. - if (too_much_bandwidth) + if (!no_bandwidth_throttling) { - return false; // wait + // Throttle on bandwidth usage. + + static size_t throttle_fraction = 1024; // A value between 0 and 1024: each service is throttled when it uses more than max_bandwidth * (throttle_fraction/1024) bandwidth. + static AIAverage fraction(25); // Average over 25 * 40ms = 1 second. + static U64 last_sTime_40ms = 0; + + // Truncate the sums to the last second, and get their value. + U64 const sTime_40ms = get_clock_count() * HTTPTimeout::sClockWidth_40ms; // Time in 40ms units. + size_t const max_bandwidth = 125.f * max_kbps; // Convert kbps to bytes per second. + size_t const total_bandwidth = BufferedCurlEasyRequest::sHTTPBandwidth.truncateData(sTime_40ms); // Bytes received in the past second. + size_t const service_bandwidth = http_bandwidth_ptr->truncateData(sTime_40ms); // Idem for just this service. + if (sTime_40ms > last_sTime_40ms) + { + // Only add throttle_fraction once every 40 ms at most. + // It's ok to ignore other values in the same 40 ms because the value only changes on the scale of 1 second. + fraction.addData(throttle_fraction, sTime_40ms); + last_sTime_40ms = sTime_40ms; + } + double fraction_avg = fraction.getAverage(1024.0); // throttle_fraction averaged over the past second, or 1024 if there is no data. + + // Adjust throttle_fraction based on total bandwidth usage. + if (total_bandwidth == 0) + throttle_fraction = 1024; + else + { + // This is the main formula. It can be made plausible by assuming + // an equilibrium where total_bandwidth == max_bandwidth and + // thus throttle_fraction == fraction_avg for more than a second. + // + // Then, more bandwidth is being used (for example because another + // service starts downloading). Assuming that all services that use + // a significant portion of the bandwidth, the new service included, + // must be throttled (all using the same bandwidth; note that the + // new service is immediately throttled at the same value), then + // the limit should be reduced linear with the fraction: + // max_bandwidth / total_bandwidth. + // + // For example, let max_bandwidth be 1. Let there be two throttled + // services, each using 0.5 (fraction_avg = 1024/2). Lets the new + // service use what it can: also 0.5 - then without reduction the + // total_bandwidth would become 1.5, and throttle_fraction would + // become (1024/2) * 1/1.5 = 1024/3: from 2 to 3 services. + // + // In reality, total_bandwidth would rise linear from 1.0 to 1.5 in + // one second if the throttle fraction wasn't changed. However it is + // changed here. The end result is that any change more or less + // linear fades away in one second. + throttle_fraction = fraction_avg * max_bandwidth / total_bandwidth; + } + if (throttle_fraction > 1024) + throttle_fraction = 1024; + if (total_bandwidth > max_bandwidth) + { + throttle_fraction *= 0.95; + } + + // Throttle this service if it uses too much bandwidth. + if (service_bandwidth > (max_bandwidth * throttle_fraction / 1024)) + { + return false; // wait + } } // Check if it's ok to get a new request based on the total number of requests and increment the threshold if appropriate. diff --git a/indra/llmessage/aihttptimeout.cpp b/indra/llmessage/aihttptimeout.cpp index 1f65b94c0..22dbb1cfd 100644 --- a/indra/llmessage/aihttptimeout.cpp +++ b/indra/llmessage/aihttptimeout.cpp @@ -97,8 +97,9 @@ namespace curlthread { // HTTPTimeout //static -F64 const HTTPTimeout::sClockWidth_10ms = 100.0 / calc_clock_frequency(); // Time between two clock ticks, in 10ms units. -U64 HTTPTimeout::sTime_10ms; // Time in 10ms units, set once per select() exit. +F64 const HTTPTimeout::sClockWidth_10ms = 100.0 / calc_clock_frequency(); // Time between two clock ticks, in 10ms units. +F64 const HTTPTimeout::sClockWidth_40ms = HTTPTimeout::sClockWidth_10ms * 0.25; // Time between two clock ticks, in 40ms units. +U64 HTTPTimeout::sTime_10ms; // Time in 10ms units, set once per select() exit. // CURL-THREAD // This is called when body data was sent to the server socket. diff --git a/indra/llmessage/aihttptimeout.h b/indra/llmessage/aihttptimeout.h index fc6db9919..1af96c9c7 100644 --- a/indra/llmessage/aihttptimeout.h +++ b/indra/llmessage/aihttptimeout.h @@ -89,6 +89,7 @@ class HTTPTimeout : public LLRefCount { U64 mStalled; // The time (sTime_10ms) at which this transaction is considered to be stalling if nothing is transfered anymore. public: static F64 const sClockWidth_10ms; // Time between two clock ticks in 10 ms units. + static F64 const sClockWidth_40ms; // Time between two clock ticks in 40 ms units. static U64 sTime_10ms; // Time since the epoch in 10 ms units. #if defined(CWDEBUG) || defined(DEBUG_CURLIO) ThreadSafeBufferedCurlEasyRequest* mLockObj; diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 8f60d2a7d..814d407d0 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -50,7 +50,6 @@ #include "lldarray.h" #include "lldir.h" #include "llerror.h" -#include "llerrorlegacy.h" #include "llfasttimer.h" #include "llhttpclient.h" #include "llhttpnodeadapter.h" diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7cefb59c6..61f8f21bc 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4921,7 +4921,18 @@ This should be as low as possible, but too low may break functionality Value -1 - DebugStatModeTexture + DebugStatModeHTTPTexture + + Comment + Mode of stat in Statistics floater + Persist + 1 + Type + S32 + Value + -1 + + DebugStatModeUDPTexture Comment Mode of stat in Statistics floater @@ -15140,6 +15151,17 @@ This should be as low as possible, but too low may break functionality Value 0 + UseTypingBubbles + + Comment + Show typing indicator in avatar nametags + Persist + 1 + Type + Boolean + Value + 0 + UseDebugMenus Comment diff --git a/indra/newview/ascentprefschat.cpp b/indra/newview/ascentprefschat.cpp index 599ab0c66..f24724279 100644 --- a/indra/newview/ascentprefschat.cpp +++ b/indra/newview/ascentprefschat.cpp @@ -329,6 +329,7 @@ void LLPrefsAscentChat::refreshValues() mHideTypingNotification = gSavedSettings.getBOOL("AscentHideTypingNotification"); mShowGroupNameInChatIM = gSavedSettings.getBOOL("OptionShowGroupNameInChatIM"); mShowDisplayNameChanges = gSavedSettings.getBOOL("ShowDisplayNameChanges"); + mUseTypingBubbles = gSavedSettings.getBOOL("UseTypingBubbles"); mPlayTypingSound = gSavedSettings.getBOOL("PlayTypingSound"); mHideNotificationsInChat = gSavedSettings.getBOOL("HideNotificationsInChat"); mEnableMUPose = gSavedSettings.getBOOL("AscentAllowMUpose"); @@ -545,6 +546,7 @@ void LLPrefsAscentChat::cancel() gSavedSettings.setBOOL("AscentHideTypingNotification", mHideTypingNotification); gSavedSettings.setBOOL("OptionShowGroupNameInChatIM", mShowGroupNameInChatIM); gSavedSettings.setBOOL("ShowDisplayNameChanges", mShowDisplayNameChanges); + gSavedSettings.setBOOL("UseTypingBubbles", mUseTypingBubbles); gSavedSettings.setBOOL("PlayTypingSound", mPlayTypingSound); gSavedSettings.setBOOL("HideNotificationsInChat", mHideNotificationsInChat); gSavedSettings.setBOOL("AscentAllowMUpose", mEnableMUPose); diff --git a/indra/newview/ascentprefschat.h b/indra/newview/ascentprefschat.h index 291645b42..04fa1a69c 100644 --- a/indra/newview/ascentprefschat.h +++ b/indra/newview/ascentprefschat.h @@ -66,6 +66,7 @@ protected: BOOL mHideTypingNotification; BOOL mShowGroupNameInChatIM; bool mShowDisplayNameChanges; + bool mUseTypingBubbles; BOOL mPlayTypingSound; BOOL mHideNotificationsInChat; BOOL mEnableMUPose; diff --git a/indra/newview/hippogridmanager.cpp b/indra/newview/hippogridmanager.cpp index b38cf0646..93168da88 100644 --- a/indra/newview/hippogridmanager.cpp +++ b/indra/newview/hippogridmanager.cpp @@ -69,42 +69,6 @@ HippoGridInfo::HippoGridInfo(const std::string& gridName) : // ******************************************************************** // Getters -HippoGridInfo::Platform HippoGridInfo::getPlatform() -{ - return mPlatform; -} - -bool HippoGridInfo::isOpenSimulator() const -{ - return (mPlatform == HippoGridInfo::PLATFORM_OPENSIM || mPlatform == HippoGridInfo::PLATFORM_AURORA); -} - -bool HippoGridInfo::isAurora() const -{ - return (mPlatform == HippoGridInfo::PLATFORM_AURORA); -} - -bool HippoGridInfo::isSecondLife() const -{ - return (mPlatform == HippoGridInfo::PLATFORM_SECONDLIFE); -} - -bool HippoGridInfo::isInProductionGrid() const -{ - llassert(mPlatform == HippoGridInfo::PLATFORM_SECONDLIFE); - return mIsInProductionGrid; -} - -bool HippoGridInfo::isAvination() const -{ - return mIsInAvination; -} - -const std::string& HippoGridInfo::getGridName() const -{ - return mGridName; -} - const std::string& HippoGridInfo::getGridOwner() const { if(isSecondLife()) @@ -118,73 +82,6 @@ const std::string& HippoGridInfo::getGridOwner() const } } -const std::string& HippoGridInfo::getLoginUri() const -{ - return mLoginUri; -} - -const std::string& HippoGridInfo::getLoginPage() const -{ - return mLoginPage; -} - -const std::string& HippoGridInfo::getHelperUri() const -{ - return mHelperUri; -} - -const std::string& HippoGridInfo::getWebSite() const -{ - return mWebSite; -} - -const std::string& HippoGridInfo::getSupportUrl() const -{ - return mSupportUrl; -} - -const std::string& HippoGridInfo::getRegisterUrl() const -{ - return mRegisterUrl; -} - -const std::string& HippoGridInfo::getPasswordUrl() const -{ - return mPasswordUrl; -} - -const std::string& HippoGridInfo::getSearchUrl() const -{ - return mSearchUrl; -} - -const std::string& HippoGridInfo::getGridMessage() const -{ - return mGridMessage; -} - -bool HippoGridInfo::isRenderCompat() const -{ - return mRenderCompat; -} - -const std::string& HippoGridInfo::getCurrencySymbol() const -{ - return mCurrencySymbol; -} - -const std::string& HippoGridInfo::getCurrencyText() const -{ - return mCurrencyText; -} - -const std::string& HippoGridInfo::getRealCurrencySymbol() const -{ - return mRealCurrencySymbol; -} - - - // ******************************************************************** // Setters @@ -484,8 +381,11 @@ void HippoGridInfo::onXmlCharacterData(void* userData, const XML_Char* s, int le { case XML_GRIDNICK: { - if (self->mGridNick == "") self->mGridNick.assign(s, len); - self->mGridNick = sanitizeGridNick(self->mGridNick); + if (self->mGridNick == "") + { + self->mGridNick.assign(s, len); + self->mGridNick = sanitizeGridNick(self->mGridNick); + } break; } @@ -517,7 +417,15 @@ void HippoGridInfo::onXmlCharacterData(void* userData, const XML_Char* s, int le break; } - case XML_GRIDNAME: self->mGridName.assign(s, len); break; + case XML_GRIDNAME: + { + if (self->mGridName == "") + { + self->mGridName.assign(s, len); + } + break; + } + case XML_LOGINPAGE: self->mLoginPage.assign(s, len); break; case XML_WEBSITE: self->mWebSite.assign(s, len); break; case XML_SUPPORT: self->mSupportUrl.assign(s, len); break; @@ -788,13 +696,6 @@ HippoGridInfo* HippoGridManager::getGrid(const std::string& grid) const } } - -HippoGridInfo* HippoGridManager::getConnectedGrid() const -{ - return (mConnectedGrid)? mConnectedGrid: getCurrentGrid(); -} - - HippoGridInfo* HippoGridManager::getCurrentGrid() const { HippoGridInfo* grid = getGrid(mCurrentGrid); diff --git a/indra/newview/hippogridmanager.h b/indra/newview/hippogridmanager.h index 1e637e521..9562d563f 100644 --- a/indra/newview/hippogridmanager.h +++ b/indra/newview/hippogridmanager.h @@ -36,33 +36,33 @@ public: explicit HippoGridInfo(const std::string& gridName); - Platform getPlatform(); - bool isOpenSimulator() const; - bool isAurora() const; - bool isSecondLife() const; - bool isAvination() const; - bool isInProductionGrid() const; // Should only be called if isSecondLife() returns true. - const std::string& getGridName() const; + Platform getPlatform() { return mPlatform; } + bool isOpenSimulator() const { return (mPlatform == PLATFORM_OPENSIM || mPlatform == PLATFORM_AURORA); } + bool isAurora() const { return (mPlatform == PLATFORM_AURORA); } + bool isSecondLife() const { return (mPlatform == PLATFORM_SECONDLIFE); } + bool isAvination() const { return mIsInAvination; } + bool isInProductionGrid() const { llassert(mPlatform == PLATFORM_SECONDLIFE); return mIsInProductionGrid; } // Should only be called if isSecondLife() returns true. + const std::string& getGridName() const { return mGridName; } const std::string& getGridOwner() const; - const std::string& getLoginUri() const; - const std::string& getLoginPage() const; - const std::string& getHelperUri() const; - const std::string& getWebSite() const; - const std::string& getSupportUrl() const; - const std::string& getRegisterUrl() const; - const std::string& getPasswordUrl() const; + const std::string& getLoginUri() const { return mLoginUri; } + const std::string& getLoginPage() const { return mLoginPage; } + const std::string& getHelperUri() const { return mHelperUri; } + const std::string& getWebSite() const { return mWebSite; } + const std::string& getSupportUrl() const { return mSupportUrl; } + const std::string& getRegisterUrl() const { return mRegisterUrl; } + const std::string& getPasswordUrl() const { return mPasswordUrl; } // Returns the url base used for the Web Search tab - const std::string& getSearchUrl() const; - const std::string& getGridMessage() const; + const std::string& getSearchUrl() const { return mSearchUrl; } + const std::string& getGridMessage() const { return mGridMessage; } const std::string& getVoiceConnector() const { return mVoiceConnector; } std::string getSearchUrl(SearchType ty, bool is_web) const; - bool isRenderCompat() const; - std::string getGridNick(); + bool isRenderCompat() const { return mRenderCompat; } + std::string getGridNick(); int getMaxAgentGroups() const { return mMaxAgentGroups; } - const std::string& getCurrencySymbol() const; - const std::string& getCurrencyText() const; - const std::string& getRealCurrencySymbol() const; + const std::string& getCurrencySymbol() const { return mCurrencySymbol; } + const std::string& getCurrencyText() const { return mCurrencyText; } + const std::string& getRealCurrencySymbol() const { return mRealCurrencySymbol; } std::string getUploadFee() const; std::string getGroupCreationFee() const; std::string getDirectoryFee() const; @@ -160,7 +160,8 @@ public: void discardAndReload(); HippoGridInfo* getGrid(const std::string& grid) const; - HippoGridInfo* getConnectedGrid() const; + HippoGridInfo* getConnectedGrid() const { return mConnectedGrid ? mConnectedGrid : getCurrentGrid(); } + HippoGridInfo* getCurrentGrid() const; const std::string& getDefaultGridNick() const; const std::string& getCurrentGridNick() const; diff --git a/indra/newview/hippopanelgrids.cpp b/indra/newview/hippopanelgrids.cpp index 61ebcdde2..6af943c5b 100644 --- a/indra/newview/hippopanelgrids.cpp +++ b/indra/newview/hippopanelgrids.cpp @@ -133,7 +133,7 @@ BOOL HippoPanelGridsImpl::postBuild() requires("btn_add"); requires("btn_copy"); requires("btn_default"); - //requires("btn_gridinfo"); + requires("btn_gridinfo"); requires("btn_help_render_compat"); if (!checkRequirements()) return false; @@ -146,7 +146,7 @@ BOOL HippoPanelGridsImpl::postBuild() childSetAction("btn_add", onClickAdd, this); childSetAction("btn_copy", onClickCopy, this); childSetAction("btn_default", onClickDefault, this); - //childSetAction("btn_gridinfo", onClickGridInfo, this); + childSetAction("btn_gridinfo", onClickGridInfo, this); childSetAction("btn_help_render_compat", onClickHelpRenderCompat, this); childSetAction("btn_advanced", onClickAdvanced, this); diff --git a/indra/newview/linux_tools/client-readme-voice.txt b/indra/newview/linux_tools/client-readme-voice.txt index 23a42f484..aa04a5704 100644 --- a/indra/newview/linux_tools/client-readme-voice.txt +++ b/indra/newview/linux_tools/client-readme-voice.txt @@ -4,14 +4,20 @@ Second Life - Linux Voice Support README WHAT IS IT? -=-=-=-=-=- -Linux Voice Support is a new feature in testing which allows users -of the Linux Second Life client to participate in voice-chat with other -residents and groups inside Second Life, with an appropriate -headset/microphone. +Linux Voice Support is a feature in testing which allows users of the Linux +Second Life client to participate in voice-chat with other residents and +groups inside Second Life, with an appropriate headset/microphone. Linux Voice Support is currently EXPERIMENTAL and is known to still have some compatibility issues. +SINGULARITY MULTI-VOICE +-=-=-=-=-=-=-=-=-=-=-=- +Singularity multi-voice is an experimental feature that allows you to run multiple +SLVoice daemons at the same time, in order to do this, the debug setting VoiceMultiInstance +must be TRUE, this allows multiple instances of the viewer to run concurrently and +each connect to voice. + REQUIREMENTS -=-=-=-=-=-= @@ -29,6 +35,13 @@ systems: * Fedora Core 6 with (unknown) audio chipset * Ubuntu 8.04 (Hardy) with (unknown) audio chipset +TESTING YOUR SETTINGS +-=-=-=-=-=-=-=-=-=-=- + +* The Second Life region 'Voice Echo Canyon' is a great place for testing +your hardware settings and quality - it will 'echo' your voice back to you +when you speak. + KNOWN PROBLEMS -=-=-=-=-=-=-= @@ -41,12 +54,12 @@ TROUBLESHOOTING PROBLEM 1: I don't see a white dot over the head of my avatar or other Voice-using avatars. SOLUTION: -a. Ensure that 'Enable voice chat' is enabled in the Voice Chat - preferences window and that you are in a voice-enabled area (you - will see a blue headphone icon in the SL menu-bar). +a. Ensure that 'Enable voice chat' is enabled in the 'Voice Chat' section of the + Preferences window, and that you are in a voice-enabled area + (you will see a blue headphone icon in the SL menu-bar). b. If the above does not help, exit Second Life and ensure that any remaining 'SLVoice' processes (as reported by 'ps', 'top' or similar) - are killed. + are killed before restarting. PROBLEM 2: I have a white dot over my head but I never see (or hear!) anyone except myself listed in the Active Speakers dialog when I'm sure that other @@ -65,12 +78,13 @@ c. Update to the latest version of ALSA manually. For a guide, see the PROBLEM 3: I can hear other people, but they cannot hear me. SOLUTION: -a. Ensure that you have the 'Talk' button activated while you are trying to - speak. +a. Ensure that you have the 'Talk' button (at the bottom of the Second Life + window)activated while you are trying to speak. b. Ensure that your microphone jack is inserted into the correct socket of your sound card, where appropriate. -c. Use your system mixer-setting program or the 'alsamixer' program to ensure - that microphone input is set as the active input source and is not muted. +c. Use your system mixer-setting program (such as the PulseAudio 'volume + control' applet or the ALSA 'alsamixer' program) to ensure that microphone + input is set as the active input source and is not muted. d. Verify that audio input works in other applications, i.e. Audacity PROBLEM 4: Other people just hear bursts of loud noise when I speak. diff --git a/indra/newview/linux_tools/client-readme.txt b/indra/newview/linux_tools/client-readme.txt index 99c973f7e..f9f60c833 100644 --- a/indra/newview/linux_tools/client-readme.txt +++ b/indra/newview/linux_tools/client-readme.txt @@ -15,7 +15,7 @@ Life itself - please see . 5.3. Blank window after minimizing it 5.4. Audio 5.5. 'Alt' key for camera controls doesn't work - 5.6. In-world streaming movie/music playback + 5.6. In-world streaming movie, music and Flash playback 6. Advanced Troubleshooting 6.1. Audio 6.2. OpenGL @@ -75,10 +75,11 @@ Life Linux client is very similar to that for Windows, as detailed at: 3. INSTALLING & RUNNING -=-=-=-=-=-=-=-=-=-=-=- -The Second Life Linux client entirely runs out of the directory you have -unpacked it into - no installation step is required. +The Singularity Linux client can entirely run from the directory you have +unpacked it into - no installation step is required. If you wish to +perform a separate installation step anyway, you may run './install.sh' -Run ./secondlife from the installation directory to start Second Life. +Run ./singularity from the installation directory to start Singularity. For in-world MOVIE and MUSIC PLAYBACK, you will need (32-bit) GStreamer 0.10 installed on your system. This is optional - it is not required for general @@ -168,12 +169,15 @@ SOLUTION:- Some window managers eat the Alt key for their own purposes; you example, the 'Windows' key!) which will allow the Alt key to function properly with mouse actions in Second Life and other applications. -PROBLEM 6:- In-world movie and/or music playback doesn't work for me. +PROBLEM 6:- In-world movie, music, or Flash playback doesn't work for me. SOLUTION:- You need to have a working installation of GStreamer 0.10; this is usually an optional package for most versions of Linux. If you have installed GStreamer 0.10 and you can play some music/movies but not others then you need to install a wider selection of GStreamer plugins, either - from your vendor or an appropriate third party. + from your vendor (i.e. the 'Ugly' plugins) or an appropriate third party. + For Flash playback, you need to have Flash 10 installed for your normal + web browser (for example, Firefox). PulseAudio is required for Flash + volume control / muting to fully function inside Second Life. 6. ADVANCED TROUBLESHOOTING diff --git a/indra/newview/linux_tools/install.sh b/indra/newview/linux_tools/install.sh new file mode 100644 index 000000000..86d020671 --- /dev/null +++ b/indra/newview/linux_tools/install.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +# Install Singularity Viewer. This script can install the viewer both +# system-wide and for an individual user. + +VT102_STYLE_NORMAL='\E[0m' +VT102_COLOR_RED='\E[31m' + +SCRIPTSRC=`readlink -f "$0" || echo "$0"` +RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` +tarball_path=${RUN_PATH} + +function prompt() +{ + local prompt=$1 + local input + + echo -n "$prompt" + + while read input; do + case $input in + [Yy]* ) + return 1 + ;; + [Nn]* ) + return 0 + ;; + * ) + echo "Please enter yes or no." + echo -n "$prompt" + esac + done +} + +function die() +{ + warn $1 + exit 1 +} + +function warn() +{ + echo -n -e $VT102_COLOR_RED + echo $1 + echo -n -e $VT102_STYLE_NORMAL +} + +function homedir_install() +{ + warn "You are not running as a privileged user, so you will only be able" + warn "to install Singularity Viewer in your home directory. If you" + warn "would like to install Singularity Viewer system-wide, please run" + warn "this script as the root user, or with the 'sudo' command." + echo + + prompt "Proceed with the installation? [Y/N]: " + if [[ $? == 0 ]]; then + exit 0 + fi + + install_to_prefix "$HOME/.singularity-install" + $HOME/.singularity-install/refresh_desktop_app_entry.sh +} + +function root_install() +{ + local default_prefix="/opt/singularity-install" + + echo -n "Enter the desired installation directory [${default_prefix}]: "; + read + if [[ "$REPLY" = "" ]] ; then + local install_prefix=$default_prefix + else + local install_prefix=$REPLY + fi + + install_to_prefix "$install_prefix" + + mkdir -p /usr/local/share/applications + ${install_prefix}/refresh_desktop_app_entry.sh +} + +function install_to_prefix() +{ + test -e "$1" && backup_previous_installation "$1" + mkdir -p "$1" || die "Failed to create installation directory!" + + echo " - Installing to $1" + + cp -a "${tarball_path}"/* "$1/" || die "Failed to complete the installation!" +} + +function backup_previous_installation() +{ + local backup_dir="$1".backup-$(date -I) + echo " - Backing up previous installation to $backup_dir" + + mv "$1" "$backup_dir" || die "Failed to create backup of existing installation!" +} + + +if [ "$UID" == "0" ]; then + root_install +else + homedir_install +fi diff --git a/indra/newview/linux_tools/refresh_desktop_app_entry.sh b/indra/newview/linux_tools/refresh_desktop_app_entry.sh new file mode 100644 index 000000000..9412c840c --- /dev/null +++ b/indra/newview/linux_tools/refresh_desktop_app_entry.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +SCRIPTSRC=`readlink -f "$0" || echo "$0"` +RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` + +install_prefix=${RUN_PATH} + +function install_desktop_entry() +{ + local installation_prefix="$1" + local desktop_entries_dir="$2" + + local desktop_entry="\ +[Desktop Entry]\n\ +Name=Singularity\n\ +Comment=Client for Online Virtual Worlds, such as Second Life\n\ +Exec=${installation_prefix}/singularity\n\ +Icon=${installation_prefix}/singularity_icon.png\n\ +Terminal=false\n\ +Type=Application\n\ +Categories=Application;Network;\n\ +StartupNotify=true\n\ +X-Desktop-File-Install-Version=3.0" + + echo " - Installing menu entries in ${desktop_entries_dir}" + mkdir -vp "${desktop_entries_dir}" + echo -e $desktop_entry > "${desktop_entries_dir}/singularity-viewer.desktop" || "Failed to install application menu!" +} + +if [ "$UID" == "0" ]; then + # system-wide + install_desktop_entry "$install_prefix" /usr/local/share/applications +else + # user-specific + install_desktop_entry "$install_prefix" "$HOME/.local/share/applications" +fi diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index e406e3c71..ff7fc48ae 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -4,10 +4,10 @@ ## These options are for self-assisted troubleshooting during this beta ## testing phase; you should not usually need to touch them. -## - Avoids using any OpenAL audio driver. -#export LL_BAD_OPENAL_DRIVER=x ## - Avoids using any FMOD Ex audio driver. #export LL_BAD_FMODEX_DRIVER=x +## - Avoids using any OpenAL audio driver. +#export LL_BAD_OPENAL_DRIVER=x ## - Avoids using any FMOD audio driver. #export LL_BAD_FMOD_DRIVER=x @@ -20,7 +20,6 @@ ## - Avoids using the FMOD or FMOD Ex ESD audio driver. #export LL_BAD_FMOD_ESD=x - ## - Avoids the optional OpenGL extensions which have proven most problematic ## on some hardware. Disabling this option may cause BETTER PERFORMANCE but ## may also cause CRASHES and hangs on some unstable combinations of drivers @@ -109,6 +108,10 @@ cd "${RUN_PATH}" # Re-register the secondlife:// protocol handler every launch, for now. ./register_secondlifeprotocol.sh + +# Re-register the application with the desktop system every launch, for now. +./refresh_desktop_app_entry.sh + ## Before we mess with LD_LIBRARY_PATH, save the old one to restore for ## subprocesses that care. export SAVED_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" @@ -147,16 +150,11 @@ fi export SL_CMD='$LL_WRAPPER bin/$VIEWER_BINARY' export SL_OPT="`cat gridargs.dat` $@" -# Run the program +# Run the program. eval ${SL_ENV} ${SL_CMD} ${SL_OPT} || LL_RUN_ERR=runerr # Handle any resulting errors -if [ -n "$LL_RUN_ERR" ]; then - LL_RUN_ERR_MSG="" - if [ "$LL_RUN_ERR" = "runerr" ]; then - # generic error running the binary - echo '*** Bad shutdown. ***' - - - fi +if [ -n "$LL_RUN_ERR" = "runerr" ]; then + # generic error running the binary + echo '*** Bad shutdown. ***' fi diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 77a0558f1..de8da30e6 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -3,10 +3,9 @@ * @brief Processes responses received for asset upload requests. * * $LicenseInfo:firstyear=2007&license=viewergpl$ - * + * Second Life Viewer Source Code * Copyright (c) 2007-2009, Linden Research, Inc. * - * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement @@ -53,7 +52,6 @@ #include "llviewerobject.h" #include "llviewercontrol.h" #include "llviewerobjectlist.h" -#include "llviewermenufile.h" #include "llviewertexlayer.h" #include "llviewerwindow.h" #include "lltrans.h" @@ -255,6 +253,7 @@ void LLAssetUploadResponder::result(const LLSD& content) lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl; std::string state = content["state"]; + if (state == "upload") { uploadUpload(content); @@ -343,6 +342,7 @@ void LLNewAgentInventoryResponder::error(U32 statusNum, const std::string& reaso //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE); } + //virtual void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content) { @@ -351,6 +351,7 @@ void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content) (*mCallBack)(false, mUserData); } LLAssetUploadResponder::uploadFailure(content); + //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], FALSE); } @@ -397,10 +398,14 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) // continue uploading for bulk uploads - if (!gUploadQueue.empty()) + /* Singu Note: sUploadQueue was never getting populated, anywhere! Therefore, this entire block never was reached. + ** I have condensed it to here in the hopes it may one day see use. Apparently, it came in with Siana's prep work + ** for mesh upload (697dd7e9298282590f8cf858a58335f70302532b), but we never needed it. + static std::deque sUploadQueue; + if (!sUploadQueue.empty()) { - std::string next_file = gUploadQueue.front(); - gUploadQueue.pop_front(); + std::string next_file = sUploadQueue.front(); + sUploadQueue.pop_front(); if (next_file.empty()) return; std::string name = gDirUtilp->getBaseFileName(next_file, true); @@ -448,6 +453,7 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) expected_upload_cost, userdata); } + */ } LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, @@ -698,6 +704,7 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) } } + ///////////////////////////////////////////////////// // LLNewAgentInventoryVariablePriceResponder::Impl // ///////////////////////////////////////////////////// @@ -1165,3 +1172,4 @@ void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog( boost::intrusive_ptr(this))); } } + diff --git a/indra/newview/llfloaterstats.cpp b/indra/newview/llfloaterstats.cpp index a60619882..a4311897e 100644 --- a/indra/newview/llfloaterstats.cpp +++ b/indra/newview/llfloaterstats.cpp @@ -238,25 +238,52 @@ void LLFloaterStats::buildStats() // Network statistics LLStatView *net_statviewp = stat_viewp->addStatView("network stat view", "Network", "OpenDebugStatNet", rect); - stat_barp = net_statviewp->addStat("Packets In", &(LLViewerStats::getInstance()->mPacketsInStat), "DebugStatModePacketsIn"); + stat_barp = net_statviewp->addStat("UDP Packets In", &(LLViewerStats::getInstance()->mPacketsInStat), "DebugStatModePacketsIn"); stat_barp->setUnitLabel("/sec"); - stat_barp = net_statviewp->addStat("Packets Out", &(LLViewerStats::getInstance()->mPacketsOutStat), "DebugStatModePacketsOut"); + stat_barp = net_statviewp->addStat("UDP Packets Out", &(LLViewerStats::getInstance()->mPacketsOutStat), "DebugStatModePacketsOut"); stat_barp->setUnitLabel("/sec"); + stat_barp = net_statviewp->addStat("HTTP Textures", &(LLViewerStats::getInstance()->mHTTPTextureKBitStat), "DebugStatModeHTTPTexture"); + stat_barp->setUnitLabel(" kbps"); + stat_barp->mMinBar = 0.f; + stat_barp->mMaxBar = gSavedSettings.getF32("HTTPThrottleBandwidth") * 2; // Times two because we'll have over shoots. + stat_barp->mTickSpacing = 1.f; + while (stat_barp->mTickSpacing < stat_barp->mMaxBar / 8) + stat_barp->mTickSpacing *= 2.f; + stat_barp->mLabelSpacing = 2 * stat_barp->mTickSpacing; + stat_barp->mPerSec = FALSE; + stat_barp->mDisplayMean = FALSE; + + stat_barp = net_statviewp->addStat("UDP Textures", &(LLViewerStats::getInstance()->mUDPTextureKBitStat), "DebugStatModeUDPTexture"); + stat_barp->setUnitLabel(" kbps"); + stat_barp->mMinBar = 0.f; + stat_barp->mMaxBar = 1024.f; + stat_barp->mTickSpacing = 128.f; + stat_barp->mLabelSpacing = 256.f; + stat_barp = net_statviewp->addStat("Objects", &(LLViewerStats::getInstance()->mObjectKBitStat), "DebugStatModeObjects"); stat_barp->setUnitLabel(" kbps"); + stat_barp->mMinBar = 0.f; + stat_barp->mMaxBar = 1024.f; + stat_barp->mTickSpacing = 128.f; + stat_barp->mLabelSpacing = 256.f; - stat_barp = net_statviewp->addStat("Texture", &(LLViewerStats::getInstance()->mTextureKBitStat), "DebugStatModeTexture"); + stat_barp = net_statviewp->addStat("Assets (UDP)", &(LLViewerStats::getInstance()->mAssetKBitStat), "DebugStatModeAsset"); stat_barp->setUnitLabel(" kbps"); + stat_barp->mMinBar = 0.f; + stat_barp->mMaxBar = 1024.f; + stat_barp->mTickSpacing = 128.f; + stat_barp->mLabelSpacing = 256.f; - stat_barp = net_statviewp->addStat("Asset", &(LLViewerStats::getInstance()->mAssetKBitStat), "DebugStatModeAsset"); + stat_barp = net_statviewp->addStat("Layers (UDP)", &(LLViewerStats::getInstance()->mLayersKBitStat), "DebugStatModeLayers"); stat_barp->setUnitLabel(" kbps"); + stat_barp->mMinBar = 0.f; + stat_barp->mMaxBar = 1024.f; + stat_barp->mTickSpacing = 128.f; + stat_barp->mLabelSpacing = 256.f; - stat_barp = net_statviewp->addStat("Layers", &(LLViewerStats::getInstance()->mLayersKBitStat), "DebugStatModeLayers"); - stat_barp->setUnitLabel(" kbps"); - - stat_barp = net_statviewp->addStat("Actual In", &(LLViewerStats::getInstance()->mActualInKBitStat), + stat_barp = net_statviewp->addStat("Actual In (UDP)", &(LLViewerStats::getInstance()->mActualInKBitStat), "DebugStatModeActualIn", TRUE, FALSE); stat_barp->setUnitLabel(" kbps"); stat_barp->mMinBar = 0.f; @@ -264,7 +291,7 @@ void LLFloaterStats::buildStats() stat_barp->mTickSpacing = 128.f; stat_barp->mLabelSpacing = 256.f; - stat_barp = net_statviewp->addStat("Actual Out", &(LLViewerStats::getInstance()->mActualOutKBitStat), + stat_barp = net_statviewp->addStat("Actual Out (UDP)", &(LLViewerStats::getInstance()->mActualOutKBitStat), "DebugStatModeActualOut", TRUE, FALSE); stat_barp->setUnitLabel(" kbps"); stat_barp->mMinBar = 0.f; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 24bed73be..cd9f44904 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -36,7 +36,7 @@ #include "lltexturefetch.h" -#include "llcurl.h" +#include "aicurl.h" #include "lldir.h" #include "llhttpclient.h" #include "llhttpstatuscodes.h" @@ -1273,7 +1273,8 @@ bool LLTextureFetchWorker::doWork(S32 param) // Let AICurl decide if we can process more HTTP requests at the moment or not. static const LLCachedControl throttle_bandwidth("HTTPThrottleBandwidth", 2000); - if (!AIPerServiceRequestQueue::wantsMoreHTTPRequestsFor(mPerServicePtr, mFetcher->getTextureBandwidth() > throttle_bandwidth)) + bool const no_bandwidth_throttling = gHippoGridManager->getConnectedGrid()->isAvination(); + if (!AIPerServiceRequestQueue::wantsMoreHTTPRequestsFor(mPerServicePtr, throttle_bandwidth, no_bandwidth_throttling)) { return false ; //wait. } @@ -1290,16 +1291,8 @@ bool LLTextureFetchWorker::doWork(S32 param) mLoaded = FALSE; mGetStatus = 0; mGetReason.clear(); - // Note: comparing mFetcher->getTextureBandwidth() with throttle_bandwidth is a bit like - // comparing apples and oranges, but it's only debug output. The first is the averaged - // bandwidth used for the body of successfully downloaded textures, averaged over roughtly - // 10 seconds, in kbits/s. The latter is the limit of the actual http curl downloads, - // including header and failures for anything (not just textures), averaged over the last - // second, also in kbits/s. - static const LLCachedControl throttle_bandwidth("HTTPThrottleBandwidth", 2000); LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << mRequestedOffset << " Bytes: " << mRequestedSize - << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << throttle_bandwidth << LL_ENDL; setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); mState = WAIT_HTTP_REQ; @@ -2041,7 +2034,6 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mBadPacketCount(0), mTextureCache(cache), mImageDecodeThread(imagedecodethread), - mTextureBandwidth(0), mHTTPTextureBits(0), mTotalHTTPRequests(0), mQAMode(qa_mode), diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 7d2d86135..d7cc94dcd 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -79,9 +79,6 @@ public: bool receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes, U16 data_size, U8* data); bool receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data); - void setTextureBandwidth(F32 bandwidth) { mTextureBandwidth = bandwidth; } - F32 getTextureBandwidth() { return mTextureBandwidth; } - // Debug BOOL isFromLocalCache(const LLUUID& id); S32 getFetchState(const LLUUID& id, F32& decode_progress_p, F32& requested_priority_p, @@ -164,7 +161,6 @@ private: queue_t mHTTPTextureQueue; typedef std::map > cancel_queue_t; cancel_queue_t mCancelQueue; - F32 mTextureBandwidth; LLTextureInfo mTextureInfo; U32 mHTTPTextureBits; diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 9e644d51a..944870e32 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -70,6 +70,7 @@ namespace AICurlInterface { U32 getNumHTTPQueued(void); U32 getNumHTTPAdded(void); U32 getNumHTTPRunning(void); + size_t getHTTPBandwidth(void); } // namespace AICurlInterface //////////////////////////////////////////////////////////////////////////// @@ -620,17 +621,15 @@ void LLGLTexMemBar::draw() text_color, LLFontGL::LEFT, LLFontGL::TOP); left += LLFontGL::getFontMonospace()->getWidth(text); - // This bandwidth is averaged over roughly 10 seconds (in kbps) and therefore pretty inaccurate. - // Also, it only takes into account actual texture data (not headers etc). But all it is used for - // is for the color of some text in the texture console, so I guess it doesn't matter. - F32 bandwidth = LLAppViewer::getTextureFetch()->getTextureBandwidth(); + // This bandwidth is averaged over 1 seconds (in kbps). + F32 bandwidth = AICurlInterface::getHTTPBandwidth() / 125.f; // Convert from bytes/s to kbps. // This is the maximum bandwidth allowed for curl transactions (of any type and averaged per second), // that is actually used to limit the number of HTTP texture requests (and only those). // Comparing that with 'bandwidth' is a bit like comparing apples and oranges, but again... who really cares. - F32 max_bandwidth = gSavedSettings.getF32("HTTPThrottleBandwidth"); + static const LLCachedControl max_bandwidth("HTTPThrottleBandwidth", 2000); color = bandwidth > max_bandwidth ? LLColor4::red : bandwidth > max_bandwidth*.75f ? LLColor4::yellow : text_color; color[VALPHA] = text_color[VALPHA]; - text = llformat("BW:%.0f/%.0f",bandwidth, max_bandwidth); + text = llformat("BW:%.0f/%.0f", bandwidth, max_bandwidth.get()); LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, v_offset + line_height*2, color, LLFontGL::LEFT, LLFontGL::TOP); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 7eb89b582..a111d95de 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -3,10 +3,9 @@ * @brief "File" menu in the main menu bar. * * $LicenseInfo:firstyear=2002&license=viewergpl$ - * + * Second Life Viewer Source Code * Copyright (c) 2002-2009, Linden Research, Inc. * - * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement @@ -63,11 +62,9 @@ #include "lltrans.h" #include "llfloaterbuycurrency.h" // -#include "llselectmgr.h" +#include "floaterlocalassetbrowse.h" #include "llassettype.h" #include "llinventorytype.h" -#include "llbvhloader.h" -#include "lllocalinventory.h" // // linden libraries @@ -89,12 +86,9 @@ #include #include "hippogridmanager.h" -#include "importtracker.h" using namespace LLOldEvents; -std::deque gUploadQueue; - typedef LLMemberListener view_listener_t; @@ -502,6 +496,15 @@ class LLFileMinimizeAllWindows : public view_listener_t return true; } }; + +class LLFileLocalAssetBrowser : public view_listener_t +{ + bool handleEvent(LLPointer, const LLSD&) + { + FloaterLocalAssetBrowser::show(0); + return true; + } +}; // class LLFileSavePreview : public view_listener_t @@ -600,20 +603,6 @@ class LLFileTakeSnapshotToDisk : public view_listener_t } }; -class LLFileLogOut : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - std::string command(gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + gDirUtilp->getExecutableFilename()); - gSavedSettings.setBOOL("ShowConsoleWindow", FALSE); - gViewerWindow->getWindow()->ShellEx(command); - gSavedSettings.setBOOL("ShowConsoleWindow", FALSE); - LLAppViewer::instance()->userQuit(); - gSavedSettings.setBOOL("ShowConsoleWindow", FALSE); - return true; - } -}; - class LLFileQuit : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -696,7 +685,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension", short_name.c_str()); args["FILE"] = short_name; - upload_error(error_message, "NofileExtension", filename, args); + upload_error(error_message, "NoFileExtension", filename, args); return; } else if (codec == IMG_CODEC_J2C) @@ -992,16 +981,10 @@ void temp_upload_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt perms->setMaskEveryone(PERM_ALL); perms->setMaskGroup(PERM_ALL); perms->setMaskNext(PERM_ALL); - - LLUUID destination = gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE); - BOOL bUseSystemInventory = (gSavedSettings.getBOOL("AscentUseSystemFolder") && gSavedSettings.getBOOL("AscentSystemTemporary")); - if (bUseSystemInventory) - { - destination = gSystemFolderAssets; - } + LLViewerInventoryItem* item = new LLViewerInventoryItem( item_id, - destination, + gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE), *perms, uuid, (LLAssetType::EType)data->mAssetInfo.mType, @@ -1011,16 +994,10 @@ void temp_upload_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt LLSaleInfo::DEFAULT, 0, time_corrected()); - if (bUseSystemInventory) - { - LLLocalInventory::addItem(item); - } - else - { - item->updateServer(TRUE); - gInventory.updateItem(item); - gInventory.notifyObservers(); - } + + item->updateServer(TRUE); + gInventory.updateItem(item); + gInventory.notifyObservers(); } else { @@ -1129,40 +1106,44 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt data = NULL; } -static LLAssetID upload_new_resource_prep(const LLTransactionID& tid, - LLAssetType::EType asset_type, - LLInventoryType::EType& inventory_type, - std::string& name, - const std::string& display_name, - std::string& description) +static LLAssetID upload_new_resource_prep( + const LLTransactionID& tid, + LLAssetType::EType asset_type, + LLInventoryType::EType& inventory_type, + std::string& name, + const std::string& display_name, + std::string& description) { LLAssetID uuid = generate_asset_id_for_new_upload(tid); increase_new_upload_stats(asset_type); - assign_defaults_and_show_upload_message(asset_type, - inventory_type, - name, - display_name, - description); + assign_defaults_and_show_upload_message( + asset_type, + inventory_type, + name, + display_name, + description); return uuid; } -LLSD generate_new_resource_upload_capability_body(LLAssetType::EType asset_type, - const std::string& name, - const std::string& desc, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms) +LLSD generate_new_resource_upload_capability_body( + LLAssetType::EType asset_type, + const std::string& name, + const std::string& desc, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms) { LLSD body; - body["folder_id"] = gInventory.findCategoryUUIDForType(destination_folder_type == LLFolderType::FT_NONE ? - LLFolderType::assetTypeToFolderType(asset_type) : - destination_folder_type); + body["folder_id"] = gInventory.findCategoryUUIDForType( + destination_folder_type == LLFolderType::FT_NONE ? + LLFolderType::assetTypeToFolderType(asset_type) : + destination_folder_type); body["asset_type"] = LLAssetType::lookup(asset_type); body["inventory_type"] = LLInventoryType::lookup(inv_type); @@ -1175,28 +1156,36 @@ LLSD generate_new_resource_upload_capability_body(LLAssetType::EType asset_type, return body; } -bool upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_type, - std::string name, - std::string desc, S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata, - void (*callback2)(bool, void*)) +bool upload_new_resource( + const LLTransactionID &tid, + LLAssetType::EType asset_type, + std::string name, + std::string desc, + S32 compression_info, + LLFolderType::EType destination_folder_type, + LLInventoryType::EType inv_type, + U32 next_owner_perms, + U32 group_perms, + U32 everyone_perms, + const std::string& display_name, + LLAssetStorage::LLStoreAssetCallback callback, + S32 expected_upload_cost, + void *userdata, + void (*callback2)(bool, void*)) { if(gDisconnected) { return false; } - - LLAssetID uuid = upload_new_resource_prep(tid, asset_type, inv_type, - name, display_name, desc); + LLAssetID uuid = + upload_new_resource_prep( + tid, + asset_type, + inv_type, + name, + display_name, + desc); llinfos << "*** Uploading: " << "\nType: " << LLAssetType::lookup(asset_type) << "\nUUID: " << uuid @@ -1216,6 +1205,7 @@ bool upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty // { llinfos << "New Agent Inventory via capability" << llendl; + LLSD body; body["folder_id"] = gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type); body["asset_type"] = LLAssetType::lookup(asset_type); @@ -1227,8 +1217,15 @@ bool upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty body["everyone_mask"] = LLSD::Integer(everyone_perms); body["expected_upload_cost"] = LLSD::Integer(expected_upload_cost); - LLHTTPClient::post(url, body, - new LLNewAgentInventoryResponder(body, uuid, asset_type, callback2, userdata)); + LLHTTPClient::post( + url, + body, + new LLNewAgentInventoryResponder( + body, + uuid, + asset_type, + callback2, + userdata)); } else { @@ -1274,12 +1271,14 @@ bool upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty { asset_callback = callback; } - gAssetStorage->storeAssetData(data->mAssetInfo.mTransactionID, data->mAssetInfo.mType, - asset_callback, - (void*)data, - temporary, - TRUE, - temporary); + gAssetStorage->storeAssetData( + data->mAssetInfo.mTransactionID, + data->mAssetInfo.mType, + asset_callback, + (void*)data, + temporary, + TRUE, + temporary); } // Return true when a call to a callback function will follow. @@ -1330,6 +1329,7 @@ void assign_defaults_and_show_upload_message(LLAssetType::EType asset_type, } LLStringUtil::stripNonprintable(name); LLStringUtil::stripNonprintable(description); + if (name.empty()) { name = "(No Name)"; @@ -1345,6 +1345,7 @@ void assign_defaults_and_show_upload_message(LLAssetType::EType asset_type, LLUploadDialog::modalUploadDialog(upload_message); } + void init_menu_file() { (new LLFileUploadImage())->registerListener(gMenuHolder, "File.UploadImage"); @@ -1358,13 +1359,13 @@ void init_menu_file() (new LLFileEnableCloseAllWindows())->registerListener(gMenuHolder, "File.EnableCloseAllWindows"); // (new LLFileMinimizeAllWindows())->registerListener(gMenuHolder, "File.MinimizeAllWindows"); + (new LLFileLocalAssetBrowser())->registerListener(gMenuHolder, "File.LocalAssetBrowser"); // (new LLFileSavePreview())->registerListener(gMenuHolder, "File.SavePreview"); (new LLFileSavePreviewPNG())->registerListener(gMenuHolder, "File.SavePreviewPNG"); (new LLFileTakeSnapshot())->registerListener(gMenuHolder, "File.TakeSnapshot"); (new LLFileTakeSnapshotToDisk())->registerListener(gMenuHolder, "File.TakeSnapshotToDisk"); (new LLFileQuit())->registerListener(gMenuHolder, "File.Quit"); - (new LLFileLogOut())->registerListener(gMenuHolder, "File.LogOut"); (new LLFileEnableUpload())->registerListener(gMenuHolder, "File.EnableUpload"); (new LLFileEnableUploadModel())->registerListener(gMenuHolder, "File.EnableUploadModel"); diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 426a5a4bf..65ff1a425 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -48,8 +48,6 @@ class NewResourceItemCallback : public LLInventoryCallback class LLTransactionID; -extern std::deque gUploadQueue; - void init_menu_file(); void upload_new_resource(const std::string& src_filename, diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 2d20f8de3..4728f0ffd 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -67,6 +67,10 @@ class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy viewerStatsResponder_timeout; +namespace AICurlInterface { +size_t getHTTPBandwidth(void); +} + class StatAttributes { public: @@ -210,7 +214,8 @@ LLViewerStats::LLViewerStats() : mLayersKBitStat("layerskbitstat"), mObjectKBitStat("objectkbitstat"), mAssetKBitStat("assetkbitstat"), - mTextureKBitStat("texturekbitstat"), + mHTTPTextureKBitStat("httptexturekbitstat"), + mUDPTextureKBitStat("udptexturekbitstat"), mMallocStat("mallocstat"), mVFSPendingOperations("vfspendingoperations"), mObjectsDrawnStat("objectsdrawnstat"), @@ -300,7 +305,8 @@ void LLViewerStats::resetStats() stats.mKBitStat.reset(); stats.mLayersKBitStat.reset(); stats.mObjectKBitStat.reset(); - stats.mTextureKBitStat.reset(); + stats.mHTTPTextureKBitStat.reset(); + stats.mUDPTextureKBitStat.reset(); stats.mVFSPendingOperations.reset(); stats.mAssetKBitStat.reset(); stats.mPacketsInStat.reset(); @@ -673,13 +679,13 @@ void update_statistics() // Only update texture stats periodically so that they are less noisy { - static const F32 texture_stats_freq = 10.f; + static const F32 texture_stats_freq = 0.25f; static LLFrameTimer texture_stats_timer; if (texture_stats_timer.getElapsedTimeF32() >= texture_stats_freq) { - stats.mTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f); + stats.mHTTPTextureKBitStat.addValue(AICurlInterface::getHTTPBandwidth()/125.f); + stats.mUDPTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f); stats.mTexturePacketsStat.addValue(LLViewerTextureList::sTexturePackets); - LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerTextureList::sTextureBits/1024.f/texture_stats_timer.getElapsedTimeF32()); gTotalTextureBytes += LLViewerTextureList::sTextureBits / 8; LLViewerTextureList::sTextureBits = 0; LLViewerTextureList::sTexturePackets = 0; diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index f7c7c0c1c..f6300d1e2 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -43,7 +43,8 @@ public: mLayersKBitStat, mObjectKBitStat, mAssetKBitStat, - mTextureKBitStat, + mHTTPTextureKBitStat, + mUDPTextureKBitStat, mVFSPendingOperations, mObjectsDrawnStat, mObjectsCulledStat, diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 0307e32a2..80efedbed 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -687,8 +687,6 @@ void LLViewerTextureList::updateImages(F32 max_time) } cleared = FALSE; - LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerStats::getInstance()->mTextureKBitStat.getMeanPerSec()); - S32 global_raw_memory; { global_raw_memory = *AIAccess(LLImageRaw::sGlobalRawMemory); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 1044f1f59..843c9ad81 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2830,14 +2830,17 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) static const LLCachedControl NAME_SHOW_TIME("RenderNameShowTime",10); // seconds static const LLCachedControl FADE_DURATION("RenderNameFadeDuration",1); // seconds static const LLCachedControl use_chat_bubbles("UseChatBubbles",false); + static const LLCachedControl use_typing_bubbles("UseTypingBubbles"); static const LLCachedControl render_name_hide_self("RenderNameHideSelf",false); static const LLCachedControl allow_nameplate_override ("CCSAllowNameplateOverride", true); -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0b +// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.2a) | Added: RLVa-0.2.0b bool fRlvShowNames = gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); // [/RLVa:KB] BOOL visible_avatar = isVisible() || mNeedsAnimUpdate; BOOL visible_chat = use_chat_bubbles && (mChats.size() || mTyping); + bool visible_typing = use_typing_bubbles && mTyping; BOOL render_name = visible_chat || + visible_typing || (visible_avatar && // [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.2a) | Added: RLVa-1.0.0h ( (!fRlvShowNames) || (RlvSettings::getShowNameTags()) ) && @@ -2871,6 +2874,11 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) mVisibleChat = visible_chat; new_name = TRUE; } + if (visible_typing != mVisibleTyping) + { + mVisibleTyping = visible_typing; + new_name = true; + } // [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.2a) | Added: RLVa-0.2.0b if (fRlvShowNames) @@ -2895,7 +2903,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) if (mAppAngle > 5.f) { const F32 START_FADE_TIME = NAME_SHOW_TIME - FADE_DURATION; - if (!visible_chat && sRenderName == RENDER_NAME_FADE && time_visible > START_FADE_TIME) + if (!visible_chat && !visible_typing && sRenderName == RENDER_NAME_FADE && time_visible > START_FADE_TIME) { alpha = 1.f - (time_visible - START_FADE_TIME) / FADE_DURATION; } @@ -3271,7 +3279,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) new_name = TRUE; } - if (mVisibleChat) + if (mVisibleChat || mVisibleTyping) { mNameText->setFont(LLFontGL::getFontSansSerif()); mNameText->setTextAlignment(LLHUDNameTag::ALIGN_TEXT_LEFT); @@ -3281,6 +3289,8 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) mNameText->clearString(); LLColor4 new_chat = gColors.getColor( "AvatarNameColor" ); + if (mVisibleChat) + { LLColor4 normal_chat = lerp(new_chat, LLColor4(0.8f, 0.8f, 0.8f, 1.f), 0.7f); LLColor4 old_chat = lerp(normal_chat, LLColor4(0.6f, 0.6f, 0.6f, 1.f), 0.7f); if (mTyping && mChats.size() >= MAX_BUBBLE_CHAT_UTTERANCES) @@ -3320,6 +3330,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) mNameText->addLine(chat_iter->mText, old_chat, style); } } + } mNameText->setVisibleOffScreen(TRUE); if (mTyping) @@ -3351,7 +3362,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font) { llassert(mNameText); - if (mVisibleChat) + if (mVisibleChat || mVisibleTyping) { mNameText->addLabel(line); } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index b4f8f12f0..90d9bcd62 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -814,6 +814,7 @@ public: void stopTyping() { mTyping = FALSE; mIdleTimer.reset();} private: BOOL mVisibleChat; + bool mVisibleTyping; //-------------------------------------------------------------------- // Lip synch morphs diff --git a/indra/newview/skins/default/xui/en-us/menu_viewer.xml b/indra/newview/skins/default/xui/en-us/menu_viewer.xml index 4cf1dd66d..988513a4b 100644 --- a/indra/newview/skins/default/xui/en-us/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en-us/menu_viewer.xml @@ -37,6 +37,9 @@ + + + @@ -44,6 +47,9 @@ + + + diff --git a/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_chat.xml b/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_chat.xml index d2bb0c5a5..b1910f032 100644 --- a/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_chat.xml +++ b/indra/newview/skins/default/xui/en-us/panel_preferences_ascent_chat.xml @@ -24,6 +24,7 @@ + Show links on chatting object names in chat history for: diff --git a/indra/newview/skins/default/xui/en-us/panel_preferences_grids.xml b/indra/newview/skins/default/xui/en-us/panel_preferences_grids.xml index f3195e5e7..28ce90ee9 100644 --- a/indra/newview/skins/default/xui/en-us/panel_preferences_grids.xml +++ b/indra/newview/skins/default/xui/en-us/panel_preferences_grids.xml @@ -30,17 +30,17 @@