Merge pull request #3583 'faster avatar loading' into release/2025.03

master
Andrey Kleshchev 2025-02-27 20:51:04 +02:00 committed by GitHub
commit 2f362aa126
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 1723 additions and 976 deletions

View File

@ -799,7 +799,6 @@ void LLAvatarAppearance::buildCharacter()
bool status = loadAvatar();
stop_glerror();
// gPrintMessagesThisFrame = true;
LL_DEBUGS() << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << LL_ENDL;
if (!status)

View File

@ -32,8 +32,6 @@
#include "lltimer.h"
#include "llhost.h"
///////////////////////////////////////////////////////////
LLPacketBuffer::LLPacketBuffer(const LLHost &host, const char *datap, const S32 size) : mHost(host)
{
mSize = 0;
@ -41,7 +39,7 @@ LLPacketBuffer::LLPacketBuffer(const LLHost &host, const char *datap, const S32
if (size > NET_BUFFER_SIZE)
{
LL_ERRS() << "Sending packet > " << NET_BUFFER_SIZE << " of size " << size << LL_ENDL;
LL_ERRS() << "Constructing packet with size=" << size << " > " << NET_BUFFER_SIZE << LL_ENDL;
}
else
{
@ -51,7 +49,6 @@ LLPacketBuffer::LLPacketBuffer(const LLHost &host, const char *datap, const S32
mSize = size;
}
}
}
LLPacketBuffer::LLPacketBuffer (S32 hSocket)
@ -59,18 +56,29 @@ LLPacketBuffer::LLPacketBuffer (S32 hSocket)
init(hSocket);
}
///////////////////////////////////////////////////////////
LLPacketBuffer::~LLPacketBuffer ()
{
}
///////////////////////////////////////////////////////////
void LLPacketBuffer::init (S32 hSocket)
void LLPacketBuffer::init(S32 hSocket)
{
mSize = receive_packet(hSocket, mData);
mHost = ::get_sender();
mReceivingIF = ::get_receiving_interface();
}
void LLPacketBuffer::init(const char* buffer, S32 data_size, const LLHost& host)
{
if (data_size > NET_BUFFER_SIZE)
{
LL_ERRS() << "Initializing packet with size=" << data_size << " > " << NET_BUFFER_SIZE << LL_ENDL;
}
else
{
memcpy(mData, buffer, data_size);
mSize = data_size;
mHost = host;
mReceivingIF = ::get_receiving_interface();
}
}

View File

@ -35,20 +35,22 @@ class LLPacketBuffer
{
public:
LLPacketBuffer(const LLHost &host, const char *datap, const S32 size);
LLPacketBuffer(S32 hSocket); // receive a packet
LLPacketBuffer(S32 hSocket); // receive a packet
~LLPacketBuffer();
S32 getSize() const { return mSize; }
const char *getData() const { return mData; }
LLHost getHost() const { return mHost; }
LLHost getReceivingInterface() const { return mReceivingIF; }
void init(S32 hSocket);
void init(const char* buffer, S32 data_size, const LLHost& host);
protected:
char mData[NET_BUFFER_SIZE]; // packet data /* Flawfinder : ignore */
S32 mSize; // size of buffer in bytes
LLHost mHost; // source/dest IP and port
LLHost mReceivingIF; // source/dest IP and port
char mData[NET_BUFFER_SIZE]; // packet data /* Flawfinder : ignore */
S32 mSize; // size of buffer in bytes
LLHost mHost; // source/dest IP and port
LLHost mReceivingIF; // source/dest IP and port
};
#endif

View File

@ -1,6 +1,6 @@
/**
* @file llpacketring.cpp
* @brief implementation of LLPacketRing class for a packet.
* @brief implementation of LLPacketRing class.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
@ -43,313 +43,44 @@
#include "message.h"
#include "u64.h"
///////////////////////////////////////////////////////////
LLPacketRing::LLPacketRing () :
mUseInThrottle(false),
mUseOutThrottle(false),
mInThrottle(256000.f),
mOutThrottle(64000.f),
mActualBitsIn(0),
mActualBitsOut(0),
mMaxBufferLength(64000),
mInBufferLength(0),
mOutBufferLength(0),
mDropPercentage(0.0f),
mPacketsToDrop(0x0)
constexpr S16 MAX_BUFFER_RING_SIZE = 1024;
constexpr S16 DEFAULT_BUFFER_RING_SIZE = 256;
LLPacketRing::LLPacketRing ()
: mPacketRing(DEFAULT_BUFFER_RING_SIZE, nullptr)
{
LLHost invalid_host;
for (size_t i = 0; i < mPacketRing.size(); ++i)
{
mPacketRing[i] = new LLPacketBuffer(invalid_host, nullptr, 0);
}
}
///////////////////////////////////////////////////////////
LLPacketRing::~LLPacketRing ()
{
cleanup();
}
///////////////////////////////////////////////////////////
void LLPacketRing::cleanup ()
{
LLPacketBuffer *packetp;
while (!mReceiveQueue.empty())
for (auto packet : mPacketRing)
{
packetp = mReceiveQueue.front();
delete packetp;
mReceiveQueue.pop();
}
while (!mSendQueue.empty())
{
packetp = mSendQueue.front();
delete packetp;
mSendQueue.pop();
delete packet;
}
mPacketRing.clear();
mNumBufferedPackets = 0;
mNumBufferedBytes = 0;
mHeadIndex = 0;
}
///////////////////////////////////////////////////////////
void LLPacketRing::dropPackets (U32 num_to_drop)
{
mPacketsToDrop += num_to_drop;
}
///////////////////////////////////////////////////////////
void LLPacketRing::setDropPercentage (F32 percent_to_drop)
{
mDropPercentage = percent_to_drop;
}
void LLPacketRing::setUseInThrottle(const bool use_throttle)
{
mUseInThrottle = use_throttle;
}
void LLPacketRing::setUseOutThrottle(const bool use_throttle)
{
mUseOutThrottle = use_throttle;
}
void LLPacketRing::setInBandwidth(const F32 bps)
{
mInThrottle.setRate(bps);
}
void LLPacketRing::setOutBandwidth(const F32 bps)
{
mOutThrottle.setRate(bps);
}
///////////////////////////////////////////////////////////
S32 LLPacketRing::receiveFromRing (S32 socket, char *datap)
{
if (mInThrottle.checkOverflow(0))
{
// We don't have enough bandwidth, don't give them a packet.
return 0;
}
LLPacketBuffer *packetp = NULL;
if (mReceiveQueue.empty())
{
// No packets on the queue, don't give them any.
return 0;
}
S32 packet_size = 0;
packetp = mReceiveQueue.front();
mReceiveQueue.pop();
packet_size = packetp->getSize();
if (packetp->getData() != NULL)
{
memcpy(datap, packetp->getData(), packet_size); /*Flawfinder: ignore*/
}
// need to set sender IP/port!!
mLastSender = packetp->getHost();
mLastReceivingIF = packetp->getReceivingInterface();
delete packetp;
this->mInBufferLength -= packet_size;
// Adjust the throttle
mInThrottle.throttleOverflow(packet_size * 8.f);
return packet_size;
}
///////////////////////////////////////////////////////////
S32 LLPacketRing::receivePacket (S32 socket, char *datap)
{
S32 packet_size = 0;
// If using the throttle, simulate a limited size input buffer.
if (mUseInThrottle)
{
bool done = false;
// push any current net packet (if any) onto delay ring
while (!done)
{
LLPacketBuffer *packetp;
packetp = new LLPacketBuffer(socket);
if (packetp->getSize())
{
mActualBitsIn += packetp->getSize() * 8;
// Fake packet loss
if (mDropPercentage && (ll_frand(100.f) < mDropPercentage))
{
mPacketsToDrop++;
}
if (mPacketsToDrop)
{
delete packetp;
packetp = NULL;
packet_size = 0;
mPacketsToDrop--;
}
}
// If we faked packet loss, then we don't have a packet
// to use for buffer overflow testing
if (packetp)
{
if (mInBufferLength + packetp->getSize() > mMaxBufferLength)
{
// Toss it.
LL_WARNS() << "Throwing away packet, overflowing buffer" << LL_ENDL;
delete packetp;
packetp = NULL;
}
else if (packetp->getSize())
{
mReceiveQueue.push(packetp);
mInBufferLength += packetp->getSize();
}
else
{
delete packetp;
packetp = NULL;
done = true;
}
}
else
{
// No packetp, keep going? - no packetp == faked packet loss
}
}
// Now, grab data off of the receive queue according to our
// throttled bandwidth settings.
packet_size = receiveFromRing(socket, datap);
}
else
{
// no delay, pull straight from net
if (LLProxy::isSOCKSProxyEnabled())
{
U8 buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
packet_size = receive_packet(socket, static_cast<char*>(static_cast<void*>(buffer)));
if (packet_size > SOCKS_HEADER_SIZE)
{
// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size - SOCKS_HEADER_SIZE);
proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
mLastSender.setAddress(header->addr);
mLastSender.setPort(ntohs(header->port));
packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
}
else
{
packet_size = 0;
}
}
else
{
packet_size = receive_packet(socket, datap);
mLastSender = ::get_sender();
}
mLastReceivingIF = ::get_receiving_interface();
if (packet_size) // did we actually get a packet?
{
if (mDropPercentage && (ll_frand(100.f) < mDropPercentage))
{
mPacketsToDrop++;
}
if (mPacketsToDrop)
{
packet_size = 0;
mPacketsToDrop--;
}
}
}
return packet_size;
bool drop = computeDrop();
return (mNumBufferedPackets > 0) ?
receiveOrDropBufferedPacket(datap, drop) :
receiveOrDropPacket(socket, datap, drop);
}
bool LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host)
bool send_packet_helper(int socket, const char * datap, S32 data_size, LLHost host)
{
bool status = true;
if (!mUseOutThrottle)
{
return sendPacketImpl(h_socket, send_buffer, buf_size, host );
}
else
{
mActualBitsOut += buf_size * 8;
LLPacketBuffer *packetp = NULL;
// See if we've got enough throttle to send a packet.
while (!mOutThrottle.checkOverflow(0.f))
{
// While we have enough bandwidth, send a packet from the queue or the current packet
S32 packet_size = 0;
if (!mSendQueue.empty())
{
// Send a packet off of the queue
LLPacketBuffer *packetp = mSendQueue.front();
mSendQueue.pop();
mOutBufferLength -= packetp->getSize();
packet_size = packetp->getSize();
status = sendPacketImpl(h_socket, packetp->getData(), packet_size, packetp->getHost());
delete packetp;
// Update the throttle
mOutThrottle.throttleOverflow(packet_size * 8.f);
}
else
{
// If the queue's empty, we can just send this packet right away.
status = sendPacketImpl(h_socket, send_buffer, buf_size, host );
packet_size = buf_size;
// Update the throttle
mOutThrottle.throttleOverflow(packet_size * 8.f);
// This was the packet we're sending now, there are no other packets
// that we need to send
return status;
}
}
// We haven't sent the incoming packet, add it to the queue
if (mOutBufferLength + buf_size > mMaxBufferLength)
{
// Nuke this packet, we overflowed the buffer.
// Toss it.
LL_WARNS() << "Throwing away outbound packet, overflowing buffer" << LL_ENDL;
}
else
{
static LLTimer queue_timer;
if ((mOutBufferLength > 4192) && queue_timer.getElapsedTimeF32() > 1.f)
{
// Add it to the queue
LL_INFOS() << "Outbound packet queue " << mOutBufferLength << " bytes" << LL_ENDL;
queue_timer.reset();
}
packetp = new LLPacketBuffer(host, send_buffer, buf_size);
mOutBufferLength += packetp->getSize();
mSendQueue.push(packetp);
}
}
return status;
}
bool LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host)
{
if (!LLProxy::isSOCKSProxyEnabled())
{
return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort());
return send_packet(socket, datap, data_size, host.getAddress(), host.getPort());
}
char headered_send_buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
@ -361,11 +92,252 @@ bool LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 bu
socks_header->atype = ADDRESS_IPV4;
socks_header->frag = 0;
memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, send_buffer, buf_size);
memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, datap, data_size);
return send_packet( h_socket,
return send_packet( socket,
headered_send_buffer,
buf_size + SOCKS_HEADER_SIZE,
data_size + SOCKS_HEADER_SIZE,
LLProxy::getInstance()->getUDPProxy().getAddress(),
LLProxy::getInstance()->getUDPProxy().getPort());
}
bool LLPacketRing::sendPacket(int socket, const char * datap, S32 data_size, LLHost host)
{
mActualBytesOut += data_size;
return send_packet_helper(socket, datap, data_size, host);
}
void LLPacketRing::dropPackets (U32 num_to_drop)
{
mPacketsToDrop += num_to_drop;
}
void LLPacketRing::setDropPercentage (F32 percent_to_drop)
{
mDropPercentage = percent_to_drop;
}
bool LLPacketRing::computeDrop()
{
bool drop= (mDropPercentage > 0.0f && (ll_frand(100.f) < mDropPercentage));
if (drop)
{
++mPacketsToDrop;
}
if (mPacketsToDrop > 0)
{
--mPacketsToDrop;
drop = true;
}
return drop;
}
S32 LLPacketRing::receiveOrDropPacket(S32 socket, char *datap, bool drop)
{
S32 packet_size = 0;
// pull straight from socket
if (LLProxy::isSOCKSProxyEnabled())
{
char buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; /* Flawfinder ignore */
packet_size = receive_packet(socket, buffer);
if (packet_size > 0)
{
mActualBytesIn += packet_size;
}
if (packet_size > SOCKS_HEADER_SIZE)
{
if (drop)
{
packet_size = 0;
}
else
{
// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size);
proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
mLastSender.setAddress(header->addr);
mLastSender.setPort(ntohs(header->port));
mLastReceivingIF = ::get_receiving_interface();
}
}
else
{
packet_size = 0;
}
}
else
{
packet_size = receive_packet(socket, datap);
if (packet_size > 0)
{
mActualBytesIn += packet_size;
if (drop)
{
packet_size = 0;
}
else
{
mLastSender = ::get_sender();
mLastReceivingIF = ::get_receiving_interface();
}
}
}
return packet_size;
}
S32 LLPacketRing::receiveOrDropBufferedPacket(char *datap, bool drop)
{
assert(mNumBufferedPackets > 0);
S32 packet_size = 0;
S16 ring_size = (S16)(mPacketRing.size());
S16 packet_index = (mHeadIndex + ring_size - mNumBufferedPackets) % ring_size;
LLPacketBuffer* packet = mPacketRing[packet_index];
packet_size = packet->getSize();
mLastSender = packet->getHost();
mLastReceivingIF = packet->getReceivingInterface();
--mNumBufferedPackets;
mNumBufferedBytes -= packet_size;
if (mNumBufferedPackets == 0)
{
assert(mNumBufferedBytes == 0);
}
if (!drop)
{
assert(packet_size > 0);
memcpy(datap, packet->getData(), packet_size);
}
else
{
packet_size = 0;
}
return packet_size;
}
S32 LLPacketRing::bufferInboundPacket(S32 socket)
{
if (mNumBufferedPackets == mPacketRing.size() && mNumBufferedPackets < MAX_BUFFER_RING_SIZE)
{
expandRing();
}
LLPacketBuffer* packet = mPacketRing[mHeadIndex];
S32 old_packet_size = packet->getSize();
S32 packet_size = 0;
if (LLProxy::isSOCKSProxyEnabled())
{
char buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; /* Flawfinder ignore */
packet_size = receive_packet(socket, buffer);
if (packet_size > 0)
{
mActualBytesIn += packet_size;
if (packet_size > SOCKS_HEADER_SIZE)
{
// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
LLHost sender;
sender.setAddress(header->addr);
sender.setPort(ntohs(header->port));
packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
packet->init(buffer + SOCKS_HEADER_SIZE, packet_size, sender);
mHeadIndex = (mHeadIndex + 1) % (S16)(mPacketRing.size());
if (mNumBufferedPackets < MAX_BUFFER_RING_SIZE)
{
++mNumBufferedPackets;
mNumBufferedBytes += packet_size;
}
else
{
// we overwrote an older packet
mNumBufferedBytes += packet_size - old_packet_size;
}
}
else
{
packet_size = 0;
}
}
}
else
{
packet->init(socket);
packet_size = packet->getSize();
if (packet_size > 0)
{
mActualBytesIn += packet_size;
mHeadIndex = (mHeadIndex + 1) % (S16)(mPacketRing.size());
if (mNumBufferedPackets < MAX_BUFFER_RING_SIZE)
{
++mNumBufferedPackets;
mNumBufferedBytes += packet_size;
}
else
{
// we overwrote an older packet
mNumBufferedBytes += packet_size - old_packet_size;
}
}
}
return packet_size;
}
S32 LLPacketRing::drainSocket(S32 socket)
{
// drain into buffer
S32 packet_size = 1;
S32 num_loops = 0;
S32 old_num_packets = mNumBufferedPackets;
while (packet_size > 0)
{
packet_size = bufferInboundPacket(socket);
++num_loops;
}
S32 num_dropped_packets = (num_loops - 1 + old_num_packets) - mNumBufferedPackets;
if (num_dropped_packets > 0)
{
LL_WARNS("Messaging") << "dropped " << num_dropped_packets << " UDP packets" << LL_ENDL;
}
return (S32)(mNumBufferedPackets);
}
bool LLPacketRing::expandRing()
{
// compute larger size
constexpr S16 BUFFER_RING_EXPANSION = 256;
S16 old_size = (S16)(mPacketRing.size());
S16 new_size = llmin(old_size + BUFFER_RING_EXPANSION, MAX_BUFFER_RING_SIZE);
if (new_size == old_size)
{
// mPacketRing is already maxed out
return false;
}
// make a larger ring and copy packet pointers
std::vector<LLPacketBuffer*> new_ring(new_size, nullptr);
for (S16 i = 0; i < old_size; ++i)
{
S16 j = (mHeadIndex + i) % old_size;
new_ring[i] = mPacketRing[j];
}
// allocate new packets for the remainder of new_ring
LLHost invalid_host;
for (S16 i = old_size; i < new_size; ++i)
{
new_ring[i] = new LLPacketBuffer(invalid_host, nullptr, 0);
}
// swap the rings and reset mHeadIndex
mPacketRing.swap(new_ring);
mHeadIndex = mNumBufferedPackets;
return true;
}

View File

@ -25,16 +25,14 @@
* $/LicenseInfo$
*/
#ifndef LL_LLPACKETRING_H
#define LL_LLPACKETRING_H
#pragma once
#include <queue>
#include <vector>
#include "llhost.h"
#include "llpacketbuffer.h"
#include "llproxy.h"
#include "llthrottle.h"
#include "net.h"
class LLPacketRing
{
@ -42,60 +40,65 @@ public:
LLPacketRing();
~LLPacketRing();
void cleanup();
// receive one packet: either buffered or from the socket
S32 receivePacket (S32 socket, char *datap);
// send one packet
bool sendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);
// drains packets from socket and returns final mNumBufferedPackets
S32 drainSocket(S32 socket);
void dropPackets(U32);
void setDropPercentage (F32 percent_to_drop);
void setUseInThrottle(const bool use_throttle);
void setUseOutThrottle(const bool use_throttle);
void setInBandwidth(const F32 bps);
void setOutBandwidth(const F32 bps);
S32 receivePacket (S32 socket, char *datap);
S32 receiveFromRing (S32 socket, char *datap);
bool sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host);
inline LLHost getLastSender() const;
inline LLHost getLastReceivingInterface() const;
inline LLHost getLastSender();
inline LLHost getLastReceivingInterface();
S32 getActualInBytes() const { return mActualBytesIn; }
S32 getActualOutBytes() const { return mActualBytesOut; }
S32 getAndResetActualInBits() { S32 bits = mActualBytesIn * 8; mActualBytesIn = 0; return bits;}
S32 getAndResetActualOutBits() { S32 bits = mActualBytesOut * 8; mActualBytesOut = 0; return bits;}
S32 getAndResetActualInBits() { S32 bits = mActualBitsIn; mActualBitsIn = 0; return bits;}
S32 getAndResetActualOutBits() { S32 bits = mActualBitsOut; mActualBitsOut = 0; return bits;}
S32 getNumBufferedPackets() const { return (S32)(mNumBufferedPackets); }
S32 getNumBufferedBytes() const { return mNumBufferedBytes; }
protected:
bool mUseInThrottle;
bool mUseOutThrottle;
// returns 'true' if we should intentionally drop a packet
bool computeDrop();
// For simulating a lower-bandwidth connection - BPS
LLThrottle mInThrottle;
LLThrottle mOutThrottle;
// returns packet_size of received packet, zero or less if no packet found
S32 receiveOrDropPacket(S32 socket, char *datap, bool drop);
S32 receiveOrDropBufferedPacket(char *datap, bool drop);
S32 mActualBitsIn;
S32 mActualBitsOut;
S32 mMaxBufferLength; // How much data can we queue up before dropping data.
S32 mInBufferLength; // Current incoming buffer length
S32 mOutBufferLength; // Current outgoing buffer length
// returns packet_size of packet buffered
S32 bufferInboundPacket(S32 socket);
F32 mDropPercentage; // % of packets to drop
U32 mPacketsToDrop; // drop next n packets
// returns 'true' if ring was expanded
bool expandRing();
std::queue<LLPacketBuffer *> mReceiveQueue;
std::queue<LLPacketBuffer *> mSendQueue;
protected:
std::vector<LLPacketBuffer*> mPacketRing;
S16 mHeadIndex { 0 };
S16 mNumBufferedPackets { 0 };
S32 mNumBufferedBytes { 0 };
S32 mActualBytesIn { 0 };
S32 mActualBytesOut { 0 };
F32 mDropPercentage { 0.0f }; // % of inbound packets to drop
U32 mPacketsToDrop { 0 }; // drop next inbound n packets
// These are the sender and receiving_interface for the last packet delivered by receivePacket()
LLHost mLastSender;
LLHost mLastReceivingIF;
private:
bool sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);
};
inline LLHost LLPacketRing::getLastSender()
inline LLHost LLPacketRing::getLastSender() const
{
return mLastSender;
}
inline LLHost LLPacketRing::getLastReceivingInterface()
inline LLHost LLPacketRing::getLastReceivingInterface() const
{
return mLastReceivingIF;
}
#endif

View File

@ -656,8 +656,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count )
// UseCircuitCode is allowed in even from an invalid circuit, so that
// we can toss circuits around.
if(
valid_packet &&
else if (
!cdp &&
(mTemplateMessageReader->getMessageName() !=
_PREHASH_UseCircuitCode))
@ -667,8 +666,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count )
valid_packet = false;
}
if(
valid_packet &&
if ( valid_packet &&
cdp &&
!cdp->getTrusted() &&
mTemplateMessageReader->isTrusted())
@ -680,7 +678,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count )
valid_packet = false;
}
if( valid_packet )
if ( valid_packet )
{
logValidMsg(cdp, host, recv_reliable, recv_resent, acks>0 );
valid_packet = mTemplateMessageReader->readMessage(buffer, host);
@ -821,6 +819,11 @@ void LLMessageSystem::processAcks(LockMessageChecker&, F32 collect_time)
}
}
S32 LLMessageSystem::drainUdpSocket()
{
return mPacketRing.drainSocket(mSocket);
}
void LLMessageSystem::copyMessageReceivedToSend()
{
// NOTE: babbage: switch builder to match reader to avoid

View File

@ -417,6 +417,9 @@ public:
bool checkMessages(LockMessageChecker&, S64 frame_count = 0 );
void processAcks(LockMessageChecker&, F32 collect_time = 0.f);
// returns total number of buffered packets after the drain
S32 drainUdpSocket();
bool isMessageFast(const char *msg);
bool isMessage(const char *msg)
{

View File

@ -76,14 +76,8 @@ static U32 gsnReceivingIFAddr = INVALID_HOST_IP_ADDRESS; // Address to which dat
const char* LOOPBACK_ADDRESS_STRING = "127.0.0.1";
const char* BROADCAST_ADDRESS_STRING = "255.255.255.255";
#if LL_DARWIN
// macOS returns an error when trying to set these to 400000. Smaller values succeed.
const int SEND_BUFFER_SIZE = 200000;
const int RECEIVE_BUFFER_SIZE = 200000;
#else // LL_DARWIN
const int SEND_BUFFER_SIZE = 400000;
const int RECEIVE_BUFFER_SIZE = 400000;
#endif // LL_DARWIN
const int SEND_BUFFER_SIZE = 200000;
const int RECEIVE_BUFFER_SIZE = 800000;
// universal functions (cross-platform)

View File

@ -349,10 +349,6 @@ std::string gLastVersionChannel;
LLVector3 gWindVec(3.0, 3.0, 0.0);
LLVector3 gRelativeWindVec(0.0, 0.0, 0.0);
U32 gPacketsIn = 0;
bool gPrintMessagesThisFrame = false;
bool gRandomizeFramerate = false;
bool gPeriodicSlowFrame = false;
@ -361,6 +357,7 @@ bool gLLErrorActivated = false;
bool gLogoutInProgress = false;
bool gSimulateMemLeak = false;
bool gDoDisconnect = false;
// We don't want anyone, especially threads working on the graphics pipeline,
// to have to block due to this WorkQueue being full.
@ -374,7 +371,6 @@ const std::string MARKER_FILE_NAME("SecondLife.exec_marker");
const std::string START_MARKER_FILE_NAME("SecondLife.start_marker");
const std::string ERROR_MARKER_FILE_NAME("SecondLife.error_marker");
const std::string LOGOUT_MARKER_FILE_NAME("SecondLife.logout_marker");
static bool gDoDisconnect = false;
static std::string gLaunchFileOnQuit;
// Used on Win32 for other apps to identify our window (eg, win_setup)
@ -1493,9 +1489,9 @@ bool LLAppViewer::doFrame()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df pauseMainloopTimeout");
pingMainloopTimeout("Main:Sleep");
pingMainloopTimeout("Main:Sleep");
pauseMainloopTimeout();
pauseMainloopTimeout();
}
// Sleep and run background threads
@ -4242,7 +4238,7 @@ U32 LLAppViewer::getTextureCacheVersion()
U32 LLAppViewer::getDiskCacheVersion()
{
// Viewer disk cache version intorduced in Simple Cache Viewer, change if the cache format changes.
const U32 DISK_CACHE_VERSION = 1;
const U32 DISK_CACHE_VERSION = 2;
return DISK_CACHE_VERSION ;
}
@ -4901,6 +4897,20 @@ void LLAppViewer::idle()
if (gTeleportDisplay)
{
if (gAgent.getTeleportState() == LLAgent::TELEPORT_ARRIVING)
{
// Teleported, but waiting for things to load, start processing surface data
{
LL_RECORD_BLOCK_TIME(FTM_NETWORK);
gVLManager.unpackData();
}
{
LL_RECORD_BLOCK_TIME(FTM_REGION_UPDATE);
const F32 max_region_update_time = .001f; // 1ms
LLWorld::getInstance()->updateRegions(max_region_update_time);
}
}
return;
}
@ -5337,12 +5347,9 @@ void LLAppViewer::idleNameCache()
// Handle messages, and all message related stuff
//
#define TIME_THROTTLE_MESSAGES
#ifdef TIME_THROTTLE_MESSAGES
#define CHECK_MESSAGES_DEFAULT_MAX_TIME .020f // 50 ms = 50 fps (just for messages!)
constexpr F32 CHECK_MESSAGES_DEFAULT_MAX_TIME = 0.020f; // 50 ms = 50 fps (just for messages!)
static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
#endif
static LLTrace::BlockTimerStatHandle FTM_IDLE_NETWORK("Idle Network");
static LLTrace::BlockTimerStatHandle FTM_MESSAGE_ACKS("Message Acks");
@ -5369,6 +5376,7 @@ void LLAppViewer::idleNetwork()
F32 total_time = 0.0f;
{
bool needs_drain = false;
LockMessageChecker lmc(gMessageSystem);
while (lmc.checkAllMessages(frame_count, gServicePump))
{
@ -5381,54 +5389,44 @@ void LLAppViewer::idleNetwork()
}
total_decoded++;
gPacketsIn++;
if (total_decoded > MESSAGE_MAX_PER_FRAME)
{
needs_drain = true;
break;
}
#ifdef TIME_THROTTLE_MESSAGES
// Prevent slow packets from completely destroying the frame rate.
// This usually happens due to clumps of avatars taking huge amount
// of network processing time (which needs to be fixed, but this is
// a good limit anyway).
total_time = check_message_timer.getElapsedTimeF32();
if (total_time >= CheckMessagesMaxTime)
{
needs_drain = true;
break;
#endif
}
}
if (needs_drain || gMessageSystem->mPacketRing.getNumBufferedPackets() > 0)
{
// Rather than allow packets to silently backup on the socket
// we drain them into our own buffer so we know how many exist.
S32 num_buffered_packets = gMessageSystem->drainUdpSocket();
if (num_buffered_packets > 0)
{
// Increase CheckMessagesMaxTime so that we will eventually catch up
CheckMessagesMaxTime *= 1.035f; // 3.5% ~= 2x in 20 frames, ~8x in 60 frames
}
}
else
{
// Reset CheckMessagesMaxTime to default value
CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
}
// Handle per-frame message system processing.
lmc.processAcks(gSavedSettings.getF32("AckCollectTime"));
}
#ifdef TIME_THROTTLE_MESSAGES
if (total_time >= CheckMessagesMaxTime)
{
// Increase CheckMessagesMaxTime so that we will eventually catch up
CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames
}
else
{
// Reset CheckMessagesMaxTime to default value
CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
}
#endif
// Decode enqueued messages...
S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded;
if( remaining_possible_decodes <= 0 )
{
LL_INFOS() << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << LL_ENDL;
}
if (gPrintMessagesThisFrame)
{
LL_INFOS() << "Decoded " << total_decoded << " msgs this frame!" << LL_ENDL;
gPrintMessagesThisFrame = false;
}
}
add(LLStatViewer::NUM_NEW_OBJECTS, gObjectList.mNumNewObjects);

View File

@ -413,11 +413,10 @@ extern std::string gLastVersionChannel;
extern LLVector3 gWindVec;
extern LLVector3 gRelativeWindVec;
extern U32 gPacketsIn;
extern bool gPrintMessagesThisFrame;
extern bool gRandomizeFramerate;
extern bool gPeriodicSlowFrame;
extern bool gDoDisconnect;
extern bool gSimulateMemLeak;

File diff suppressed because it is too large Load Diff

View File

@ -63,6 +63,16 @@ typedef enum e_mesh_processing_result_enum
MESH_UNKNOWN
} EMeshProcessingResult;
typedef enum e_mesh_request_type_enum
{
MESH_REQUEST_HEADER,
MESH_REQUEST_LOD,
MESH_REQUEST_SKIN,
MESH_REQUEST_DECOMPOSITION,
MESH_REQUEST_PHYSICS,
MESH_REQUEST_UKNOWN
} EMeshRequestType;
class LLMeshUploadData
{
public:
@ -183,7 +193,8 @@ public:
class RequestStats
{
public:
RequestStats() : mRetries(0) {};
RequestStats() :mRetries(0) {};
void updateTime();
bool canRetry() const;
@ -195,6 +206,67 @@ private:
LLFrameTimer mTimer;
};
class PendingRequestBase
{
public:
struct CompareScoreGreater
{
bool operator()(const std::unique_ptr<PendingRequestBase>& lhs, const std::unique_ptr<PendingRequestBase>& rhs)
{
return lhs->mScore > rhs->mScore; // greatest = first
}
};
PendingRequestBase() : mScore(0.f) {};
virtual ~PendingRequestBase() {}
bool operator<(const PendingRequestBase& rhs) const
{
return mId < rhs.mId;
}
void setScore(F32 score) { mScore = score; }
F32 getScore() const { return mScore; }
LLUUID getId() const { return mId; }
virtual EMeshRequestType getRequestType() const = 0;
protected:
F32 mScore;
LLUUID mId;
};
class PendingRequestLOD : public PendingRequestBase
{
public:
LLVolumeParams mMeshParams;
S32 mLOD;
PendingRequestLOD(const LLVolumeParams& mesh_params, S32 lod)
: PendingRequestBase(), mMeshParams(mesh_params), mLOD(lod)
{
mId = mMeshParams.getSculptID();
}
EMeshRequestType getRequestType() const override { return MESH_REQUEST_LOD; }
};
class PendingRequestUUID : public PendingRequestBase
{
public:
PendingRequestUUID(const LLUUID& id, EMeshRequestType type)
: PendingRequestBase(), mRequestType(type)
{
mId = id;
}
EMeshRequestType getRequestType() const override { return mRequestType; }
private:
EMeshRequestType mRequestType;
};
class LLMeshHeader
{
public:
@ -235,19 +307,67 @@ public:
m404 = header.has("404");
}
private:
enum EDiskCacheFlags {
FLAG_SKIN = 1 << LLModel::NUM_LODS,
FLAG_PHYSCONVEX = 1 << (LLModel::NUM_LODS + 1),
FLAG_PHYSMESH = 1 << (LLModel::NUM_LODS + 2),
};
public:
U32 getFlags()
{
U32 flags = 0;
for (U32 i = 0; i < LLModel::NUM_LODS; i++)
{
if (mLodInCache[i])
{
flags |= 1 << i;
}
}
if (mSkinInCache)
{
flags |= FLAG_SKIN;
}
if (mPhysicsConvexInCache)
{
flags |= FLAG_PHYSCONVEX;
}
if (mPhysicsMeshInCache)
{
flags |= FLAG_PHYSMESH;
}
return flags;
}
void setFromFlags(U32 flags)
{
for (U32 i = 0; i < LLModel::NUM_LODS; i++)
{
mLodInCache[i] = (flags & (1 << i)) != 0;
}
mSkinInCache = (flags & FLAG_SKIN) != 0;
mPhysicsConvexInCache = (flags & FLAG_PHYSCONVEX) != 0;
mPhysicsMeshInCache = (flags & FLAG_PHYSMESH) != 0;
}
S32 mVersion = -1;
S32 mSkinOffset = -1;
S32 mSkinSize = -1;
bool mSkinInCache = false;
S32 mPhysicsConvexOffset = -1;
S32 mPhysicsConvexSize = -1;
bool mPhysicsConvexInCache = false;
S32 mPhysicsMeshOffset = -1;
S32 mPhysicsMeshSize = -1;
bool mPhysicsMeshInCache = false;
S32 mLodOffset[4] = { -1 };
S32 mLodSize[4] = { -1 };
S32 mLodOffset[LLModel::NUM_LODS] = { -1 };
S32 mLodSize[LLModel::NUM_LODS] = { -1 };
bool mLodInCache[LLModel::NUM_LODS] = { false };
S32 mHeaderSize = -1;
bool m404 = false;
};
@ -258,6 +378,7 @@ public:
static std::atomic<S32> sActiveHeaderRequests;
static std::atomic<S32> sActiveLODRequests;
static std::atomic<S32> sActiveSkinRequests;
static U32 sMaxConcurrentRequests;
static S32 sRequestLowWater;
static S32 sRequestHighWater;
@ -265,10 +386,13 @@ public:
LLMutex* mMutex;
LLMutex* mHeaderMutex;
LLMutex* mLoadedMutex;
LLMutex* mPendingMutex;
LLMutex* mSkinMapMutex;
LLCondition* mSignal;
//map of known mesh headers
typedef boost::unordered_map<LLUUID, std::pair<U32, LLMeshHeader>> mesh_header_map; // pair is header_size and data
typedef boost::unordered_map<LLUUID, LLMeshHeader> mesh_header_map; // pair is header_size and data
mesh_header_map mMeshHeader;
class HeaderRequest : public RequestStats
@ -292,22 +416,13 @@ public:
public:
LLVolumeParams mMeshParams;
S32 mLOD;
F32 mScore;
LODRequest(const LLVolumeParams& mesh_params, S32 lod)
: RequestStats(), mMeshParams(mesh_params), mLOD(lod), mScore(0.f)
: RequestStats(), mMeshParams(mesh_params), mLOD(lod)
{
}
};
struct CompareScoreGreater
{
bool operator()(const LODRequest& lhs, const LODRequest& rhs)
{
return lhs.mScore > rhs.mScore; // greatest = first
}
};
class UUIDBasedRequest : public RequestStats
{
public:
@ -369,7 +484,7 @@ public:
std::deque<LoadedMesh> mLoadedQ;
//map of pending header requests and currently desired LODs
typedef std::unordered_map<LLUUID, std::vector<S32> > pending_lod_map;
typedef std::unordered_map<LLUUID, std::array<S32, LLModel::NUM_LODS> > pending_lod_map;
pending_lod_map mPendingLOD;
// map of mesh ID to skin info (mirrors LLMeshRepository::mSkinMap)
@ -379,6 +494,8 @@ public:
// workqueue for processing generic requests
LL::WorkQueue mWorkQueue;
// lods have their own thread due to costly cacheOptimize() calls
std::unique_ptr<LL::ThreadPool> mMeshThreadPool;
// llcorehttp library interface objects.
LLCore::HttpStatus mHttpStatus;
@ -402,16 +519,16 @@ public:
void lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
void loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
bool fetchMeshHeader(const LLVolumeParams& mesh_params, bool can_retry = true);
bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, bool can_retry = true);
EMeshProcessingResult headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size);
bool fetchMeshHeader(const LLVolumeParams& mesh_params);
bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
EMeshProcessingResult headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size, U32 flags = 0);
EMeshProcessingResult lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size);
bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
bool decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
EMeshProcessingResult physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
bool hasPhysicsShapeInHeader(const LLUUID& mesh_id);
bool hasSkinInfoInHeader(const LLUUID& mesh_id);
bool hasHeader(const LLUUID& mesh_id);
bool hasPhysicsShapeInHeader(const LLUUID& mesh_id) const;
bool hasSkinInfoInHeader(const LLUUID& mesh_id) const;
bool hasHeader(const LLUUID& mesh_id) const;
void notifyLoadedMeshes();
S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
@ -422,7 +539,7 @@ public:
//send request for skin info, returns true if header info exists
// (should hold onto mesh_id and try again later if header info does not exist)
bool fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry = true);
bool fetchMeshSkinInfo(const LLUUID& mesh_id);
//send request for decomposition, returns true if header info exists
// (should hold onto mesh_id and try again later if header info does not exist)
@ -436,6 +553,8 @@ public:
static void decActiveLODRequests();
static void incActiveHeaderRequests();
static void decActiveHeaderRequests();
static void incActiveSkinRequests();
static void decActiveSkinRequests();
// Set the caps strings and preferred version for constructing
// mesh fetch URLs.
@ -456,6 +575,14 @@ private:
LLCore::HttpHandle getByteRange(const std::string & url,
size_t offset, size_t len,
const LLCore::HttpHandler::ptr_t &handler);
// Mutex: acquires mPendingMutex, mMutex and mHeaderMutex as needed
void loadMeshLOD(const LLUUID &mesh_id, const LLVolumeParams& mesh_params, S32 lod);
// Threads: Repo thread only
U8* getDiskCacheBuffer(S32 size);
S32 mDiskCacheBufferSize = 0;
U8* mDiskCacheBuffer = nullptr;
};
@ -568,35 +695,35 @@ public:
bool init(const LLMeshHeader& header);
// Size for given LOD
S32 getSizeByLOD(S32 lod);
S32 getSizeByLOD(S32 lod) const;
// Sum of all LOD sizes.
S32 getSizeTotal();
S32 getSizeTotal() const;
// Estimated triangle counts for the given LOD.
F32 getEstTrisByLOD(S32 lod);
F32 getEstTrisByLOD(S32 lod) const;
// Estimated triangle counts for the largest LOD. Typically this
// is also the "high" LOD, but not necessarily.
F32 getEstTrisMax();
F32 getEstTrisMax() const;
// Triangle count as computed by original streaming cost
// formula. Triangles in each LOD are weighted based on how
// frequently they will be seen.
// This was called "unscaled_value" in the original getStreamingCost() functions.
F32 getRadiusWeightedTris(F32 radius);
F32 getRadiusWeightedTris(F32 radius) const;
// Triangle count used by triangle-based cost formula. Based on
// triangles in highest LOD plus potentially partial charges for
// lower LODs depending on complexity.
F32 getEstTrisForStreamingCost();
F32 getEstTrisForStreamingCost() const;
// Streaming cost. This should match the server-side calculation
// for the corresponding volume.
F32 getRadiusBasedStreamingCost(F32 radius);
F32 getRadiusBasedStreamingCost(F32 radius) const;
// New streaming cost formula, currently only used for animated objects.
F32 getTriangleBasedStreamingCost();
F32 getTriangleBasedStreamingCost() const;
private:
// From the "size" field of the mesh header. LOD 0=lowest, 3=highest.
@ -620,12 +747,12 @@ public:
static U32 sLODPending;
static U32 sLODProcessing;
static U32 sCacheBytesRead;
static U32 sCacheBytesWritten;
static std::atomic<U32> sCacheBytesWritten;
static U32 sCacheBytesHeaders;
static U32 sCacheBytesSkins;
static U32 sCacheBytesDecomps;
static U32 sCacheReads;
static U32 sCacheWrites;
static std::atomic<U32> sCacheWrites;
static U32 sMaxLockHoldoffs; // Maximum sequential locking failures
static LLDeadmanTimer sQuiescentTimer; // Time-to-complete-mesh-downloads after significant events
@ -646,11 +773,11 @@ public:
void unregisterMesh(LLVOVolume* volume);
//mesh management functions
S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1);
S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 new_lod = 0, S32 last_lod = -1);
void notifyLoadedMeshes();
void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);
void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod);
void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume, S32 lod);
void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 request_lod, S32 volume_lod);
void notifySkinInfoReceived(LLMeshSkinInfo* info);
void notifySkinInfoUnavailable(const LLUUID& info);
void notifyDecompositionReceived(LLModel::Decomposition* info);
@ -662,7 +789,7 @@ public:
void fetchPhysicsShape(const LLUUID& mesh_id);
bool hasPhysicsShape(const LLUUID& mesh_id);
bool hasSkinInfo(const LLUUID& mesh_id);
bool hasHeader(const LLUUID& mesh_id);
bool hasHeader(const LLUUID& mesh_id) const;
void buildHull(const LLVolumeParams& params, S32 detail);
void buildPhysicsMesh(LLModel::Decomposition& decomp);
@ -676,7 +803,7 @@ public:
LLHandle<LLWholeModelFeeObserver> fee_observer= (LLHandle<LLWholeModelFeeObserver>()),
LLHandle<LLWholeModelUploadObserver> upload_observer = (LLHandle<LLWholeModelUploadObserver>()));
S32 getMeshSize(const LLUUID& mesh_id, S32 lod);
S32 getMeshSize(const LLUUID& mesh_id, S32 lod) const;
// Quiescent timer management, main thread only.
static void metricsStart();
@ -684,7 +811,7 @@ public:
static void metricsProgress(unsigned int count);
static void metricsUpdate();
typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > mesh_load_map;
typedef std::unordered_map<LLUUID, std::vector<LLVOVolume*> > mesh_load_map;
mesh_load_map mLoadingMeshes[4];
typedef std::unordered_map<LLUUID, LLPointer<LLMeshSkinInfo>> skin_map;
@ -695,15 +822,13 @@ public:
LLMutex* mMeshMutex;
std::vector<LLMeshRepoThread::LODRequest> mPendingRequests;
typedef std::vector <std::unique_ptr<PendingRequestBase> > pending_requests_vec;
pending_requests_vec mPendingRequests;
//list of mesh ids awaiting skin info
typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > skin_load_map;
typedef std::unordered_map<LLUUID, std::vector<LLVOVolume*> > skin_load_map;
skin_load_map mLoadingSkins;
//list of mesh ids that need to send skin info fetch requests
std::queue<LLUUID> mPendingSkinRequests;
//list of mesh ids awaiting decompositions
std::unordered_set<LLUUID> mLoadingDecompositions;

View File

@ -297,16 +297,62 @@ void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is
// exported functionality
//
void do_startup_frame()
{
// Until after STATE_AGENT_SEND we don't get very many UDP packets to poll the socket,
// and after STATE_PRECACHE the LLAppViewer::idleNetwork() will do UDP processing,
// so we only bother to process between those two states.
EStartupState state = LLStartUp::getStartupState();
if (state > STATE_AGENT_SEND && state < STATE_PRECACHE)
{
// drain the UDP socket...
U64 t0 = totalTime();
constexpr U64 MAX_STARTUP_FRAME_TIME = 2000; // usec
constexpr U64 MAX_STARTUP_FRAME_MESSAGES = 100;
S32 num_messages = 0;
bool needs_drain = false;
LockMessageChecker lmc(gMessageSystem);
while (lmc.checkAllMessages(gFrameCount, gServicePump))
{
if (gDoDisconnect)
{
// We're disconnecting, don't process any more messages from the server
// We're usually disconnecting due to either network corruption or a
// server going down, so this is OK.
break;
}
if (++num_messages >= MAX_STARTUP_FRAME_MESSAGES
|| (totalTime() - t0) > MAX_STARTUP_FRAME_TIME)
{
needs_drain = true;
break;
}
}
if (needs_drain || gMessageSystem->mPacketRing.getNumBufferedPackets() > 0)
{
gMessageSystem->drainUdpSocket();
}
lmc.processAcks();
}
// ...then call display_startup()
display_startup();
}
void pump_idle_startup_network(void)
{
// while there are message to process:
// process one then call display_startup()
S32 num_messages = 0;
{
LockMessageChecker lmc(gMessageSystem);
while (lmc.checkAllMessages(gFrameCount, gServicePump))
{
display_startup();
++num_messages;
}
lmc.processAcks();
}
// finally call one last display_startup()
display_startup();
}
@ -623,21 +669,6 @@ bool idle_startup()
F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage");
msg->mPacketRing.setDropPercentage(dropPercent);
F32 inBandwidth = gSavedSettings.getF32("InBandwidth");
F32 outBandwidth = gSavedSettings.getF32("OutBandwidth");
if (inBandwidth != 0.f)
{
LL_DEBUGS("AppInit") << "Setting packetring incoming bandwidth to " << inBandwidth << LL_ENDL;
msg->mPacketRing.setUseInThrottle(true);
msg->mPacketRing.setInBandwidth(inBandwidth);
}
if (outBandwidth != 0.f)
{
LL_DEBUGS("AppInit") << "Setting packetring outgoing bandwidth to " << outBandwidth << LL_ENDL;
msg->mPacketRing.setUseOutThrottle(true);
msg->mPacketRing.setOutBandwidth(outBandwidth);
}
}
LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL;
@ -743,7 +774,7 @@ bool idle_startup()
LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL;
std::string msg = LLTrans::getString("LoginInitializingBrowser");
set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str());
display_startup();
do_startup_frame();
// LLViewerMedia::initBrowser();
LLStartUp::setStartupState( STATE_LOGIN_SHOW );
return false;
@ -808,7 +839,7 @@ bool idle_startup()
LL_DEBUGS("AppInit") << "FirstLoginThisInstall off" << LL_ENDL;
}
}
display_startup();
do_startup_frame();
LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input
}
else
@ -839,7 +870,7 @@ bool idle_startup()
}
LL_DEBUGS("AppInit") << "PeekMessage processed" << LL_ENDL;
#endif
display_startup();
do_startup_frame();
timeout.reset();
return false;
}
@ -854,7 +885,7 @@ bool idle_startup()
// Don't do anything. Wait for the login view to call the login_callback,
// which will push us to the next state.
// display() function will be the one to run display_startup()
// display() function will be the one to run do_startup_frame()
// Sleep so we don't spin the CPU
ms_sleep(1);
return false;
@ -1036,7 +1067,7 @@ bool idle_startup()
auth_desc = LLTrans::getString("LoginInProgress");
set_startup_status(progress, auth_desc, auth_message);
progress += 0.02f;
display_startup();
do_startup_frame();
// Setting initial values...
LLLoginInstance* login = LLLoginInstance::getInstance();
@ -1073,7 +1104,7 @@ bool idle_startup()
emsg << LLTrans::getString("LoginFailedHeader") << "\n";
if(LLLoginInstance::getInstance()->authFailure())
{
LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): "
LL_INFOS("LLStartUp") << "Login failed, LLLoginInstance::getResponse(): "
<< LLLoginInstance::getInstance()->getResponse() << LL_ENDL;
LLSD response = LLLoginInstance::getInstance()->getResponse();
// Still have error conditions that may need some
@ -1145,7 +1176,7 @@ bool idle_startup()
// If optional was skipped this case shouldn't
// be reached.
LL_INFOS("LLStartup") << "Forcing a quit due to update." << LL_ENDL;
LL_INFOS("LLStartUp") << "Forcing a quit due to update." << LL_ENDL;
LLLoginInstance::getInstance()->disconnect();
LLAppViewer::instance()->forceQuit();
}
@ -1173,7 +1204,7 @@ bool idle_startup()
}
catch (LLCertException &cert_exception)
{
LL_WARNS("LLStartup", "SECAPI") << "Caught " << cert_exception.what() << " certificate expception on getCertificate("<< response["certificate"] << ")" << LL_ENDL;
LL_WARNS("LLStartUp", "SECAPI") << "Caught " << cert_exception.what() << " certificate expception on getCertificate("<< response["certificate"] << ")" << LL_ENDL;
LLSD args;
args["REASON"] = LLTrans::getString(cert_exception.what());
@ -1225,7 +1256,7 @@ bool idle_startup()
// notificatioin message.
LLSD args;
args["ERROR_MESSAGE"] = emsg.str();
LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
LL_INFOS("LLStartUp") << "Notification: " << args << LL_ENDL;
LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
}
}
@ -1248,7 +1279,7 @@ bool idle_startup()
{
LLSD args;
args["ERROR_MESSAGE"] = emsg.str();
LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
LL_INFOS("LLStartUp") << "Notification: " << args << LL_ENDL;
LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
transition_back_to_login_panel(emsg.str());
show_connect_box = true;
@ -1264,71 +1295,71 @@ bool idle_startup()
if (STATE_WORLD_INIT == LLStartUp::getStartupState())
{
set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD);
display_startup();
do_startup_frame();
// We should have an agent id by this point.
llassert(!(gAgentID == LLUUID::null));
// Finish agent initialization. (Requires gSavedSettings, builds camera)
gAgent.init();
display_startup();
do_startup_frame();
gAgentCamera.init();
display_startup();
display_startup();
do_startup_frame();
do_startup_frame();
// Since we connected, save off the settings so the user doesn't have to
// type the name/password again if we crash.
gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), true);
LLUIColorTable::instance().saveUserSettings();
display_startup();
do_startup_frame();
//
// Initialize classes w/graphics stuff.
//
LLSurface::initClasses();
display_startup();
do_startup_frame();
display_startup();
do_startup_frame();
LLDrawable::initClass();
display_startup();
do_startup_frame();
// init the shader managers
LLPostProcess::initClass();
display_startup();
do_startup_frame();
LLAvatarAppearance::initClass("avatar_lad.xml","avatar_skeleton.xml");
display_startup();
do_startup_frame();
LLViewerObject::initVOClasses();
display_startup();
do_startup_frame();
// Initialize all our tools. Must be done after saved settings loaded.
// NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton.
LLToolMgr::getInstance()->initTools();
display_startup();
do_startup_frame();
// Pre-load floaters, like the world map, that are slow to spawn
// due to XML complexity.
gViewerWindow->initWorldUI();
display_startup();
do_startup_frame();
// This is where we used to initialize gWorldp. Original comment said:
// World initialization must be done after above window init
// User might have overridden far clip
LLWorld::getInstance()->setLandFarClip(gAgentCamera.mDrawDistance);
display_startup();
do_startup_frame();
// Before we create the first region, we need to set the agent's mOriginGlobal
// This is necessary because creating objects before this is set will result in a
// bad mPositionAgent cache.
gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle));
display_startup();
do_startup_frame();
LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim);
display_startup();
do_startup_frame();
LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle);
LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL;
@ -1337,18 +1368,18 @@ bool idle_startup()
<< gFirstSimSeedCap << LL_ENDL;
regionp->setSeedCapability(gFirstSimSeedCap);
LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL;
display_startup();
do_startup_frame();
// Set agent's initial region to be the one we just created.
gAgent.setRegion(regionp);
display_startup();
do_startup_frame();
// Set agent's initial position, which will be read by LLVOAvatar when the avatar
// object is created. I think this must be done after setting the region. JC
gAgent.setPositionAgent(agent_start_position_region);
display_startup();
do_startup_frame();
LLStartUp::initExperiences();
display_startup();
do_startup_frame();
// If logging should be enebled, turns it on and loads history from disk
// Note: does not happen on init of singleton because preferences can use
@ -1369,7 +1400,7 @@ bool idle_startup()
{
LLStartUp::multimediaInit();
LLStartUp::setStartupState( STATE_FONT_INIT );
display_startup();
do_startup_frame();
return false;
}
@ -1378,7 +1409,7 @@ bool idle_startup()
{
LLStartUp::fontInit();
LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT );
display_startup();
do_startup_frame();
return false;
}
@ -1450,7 +1481,7 @@ bool idle_startup()
set_startup_status(0.4f, LLTrans::getString("LoginRequestSeedCapGrant"), gAgent.mMOTD.c_str());
}
}
display_startup();
do_startup_frame();
return false;
}
@ -1461,7 +1492,7 @@ bool idle_startup()
//---------------------------------------------------------------------
if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState())
{
display_startup();
do_startup_frame();
// These textures are not warrantied to be cached, so needs
// to hapen with caps granted
@ -1470,9 +1501,9 @@ bool idle_startup()
// will init images, should be done with caps, but before gSky.init()
LLEnvironment::getInstance()->initSingleton();
display_startup();
do_startup_frame();
update_texture_fetch();
display_startup();
do_startup_frame();
if ( gViewerWindow != NULL)
{ // This isn't the first logon attempt, so show the UI
@ -1480,15 +1511,15 @@ bool idle_startup()
}
gLoginMenuBarView->setVisible( false );
gLoginMenuBarView->setEnabled( false );
display_startup();
do_startup_frame();
// direct logging to the debug console's line buffer
LLError::logToFixedBuffer(gDebugView->mDebugConsolep);
display_startup();
do_startup_frame();
// set initial visibility of debug console
gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole"));
display_startup();
do_startup_frame();
//
// Set message handlers
@ -1497,23 +1528,23 @@ bool idle_startup()
// register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted
register_viewer_callbacks(gMessageSystem);
display_startup();
do_startup_frame();
// Debugging info parameters
gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms
display_startup();
do_startup_frame();
#ifndef LL_RELEASE_FOR_DOWNLOAD
gMessageSystem->setTimeDecodes( true ); // Time the decode of each msg
gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode
#endif
display_startup();
do_startup_frame();
gXferManager->registerCallbacks(gMessageSystem);
display_startup();
do_startup_frame();
LLStartUp::initNameCache();
display_startup();
do_startup_frame();
// update the voice settings *after* gCacheName initialization
// so that we can construct voice UI that relies on the name cache
@ -1521,7 +1552,7 @@ bool idle_startup()
{
LLVoiceClient::getInstance()->updateSettings();
}
display_startup();
do_startup_frame();
// create a container's instance for start a controlling conversation windows
// by the voice's events
@ -1542,12 +1573,12 @@ bool idle_startup()
// register null callbacks for audio until the audio system is initialized
gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL);
gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL);
display_startup();
do_startup_frame();
//reset statistics
LLViewerStats::instance().resetStats();
display_startup();
do_startup_frame();
//
// Set up region and surface defaults
//
@ -1572,7 +1603,7 @@ bool idle_startup()
LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio());
// Initialize FOV
LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle"));
display_startup();
do_startup_frame();
// Move agent to starting location. The position handed to us by
// the space server is in global coordinates, but the agent frame
@ -1583,7 +1614,7 @@ bool idle_startup()
gAgent.resetAxes(gAgentStartLookAt);
gAgentCamera.stopCameraAnimation();
gAgentCamera.resetCamera();
display_startup();
do_startup_frame();
// Initialize global class data needed for surfaces (i.e. textures)
LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
@ -1594,7 +1625,7 @@ bool idle_startup()
LLGLState::checkStates();
display_startup();
do_startup_frame();
LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL;
// For all images pre-loaded into viewer cache, init
@ -1608,12 +1639,12 @@ bool idle_startup()
{
F32 frac = (F32)i / (F32)DECODE_TIME_SEC;
set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD);
display_startup();
do_startup_frame();
gTextureList.decodeAllImages(1.f);
}
LLStartUp::setStartupState( STATE_WORLD_WAIT );
display_startup();
do_startup_frame();
// JC - Do this as late as possible to increase likelihood Purify
// will run.
@ -1642,7 +1673,7 @@ bool idle_startup()
NULL);
timeout.reset();
display_startup();
do_startup_frame();
return false;
}
@ -1669,7 +1700,7 @@ bool idle_startup()
{
LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL;
set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD);
display_startup();
do_startup_frame();
// register with the message system so it knows we're
// expecting this message
LLMessageSystem* msg = gMessageSystem;
@ -1683,7 +1714,7 @@ bool idle_startup()
gAssetStorage->setUpstream(regionp->getHost());
gCacheName->setUpstream(regionp->getHost());
}
display_startup();
do_startup_frame();
// Create login effect
// But not on first login, because you can't see your avatar then
@ -1698,7 +1729,7 @@ bool idle_startup()
LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT
timeout.reset();
display_startup();
do_startup_frame();
return false;
}
@ -1707,35 +1738,13 @@ bool idle_startup()
//---------------------------------------------------------------------
if (STATE_AGENT_WAIT == LLStartUp::getStartupState())
{
{
LockMessageChecker lmc(gMessageSystem);
while (lmc.checkAllMessages(gFrameCount, gServicePump))
{
if (gAgentMovementCompleted)
{
// Sometimes we have more than one message in the
// queue. break out of this loop and continue
// processing. If we don't, then this could skip one
// or more login steps.
break;
}
else
{
LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got "
<< gMessageSystem->getMessageName() << LL_ENDL;
}
display_startup();
}
lmc.processAcks();
}
display_startup();
do_startup_frame();
if (gAgentMovementCompleted)
{
LLStartUp::setStartupState( STATE_INVENTORY_SEND );
}
display_startup();
do_startup_frame();
if (!gAgentMovementCompleted && timeout.getElapsedTimeF32() > STATE_AGENT_WAIT_TIMEOUT)
{
@ -1768,7 +1777,7 @@ bool idle_startup()
if (STATE_INVENTORY_SEND == LLStartUp::getStartupState())
{
LL_PROFILE_ZONE_NAMED("State inventory send")
display_startup();
do_startup_frame();
// request mute list
LL_INFOS() << "Requesting Mute List" << LL_ENDL;
@ -1778,12 +1787,12 @@ bool idle_startup()
LL_INFOS() << "Requesting Money Balance" << LL_ENDL;
LLStatusBar::sendMoneyBalanceRequest();
display_startup();
do_startup_frame();
// Inform simulator of our language preference
LLAgentLanguage::update();
display_startup();
do_startup_frame();
// unpack thin inventory
LLSD response = LLLoginInstance::getInstance()->getResponse();
//bool dump_buffer = false;
@ -1798,7 +1807,7 @@ bool idle_startup()
gInventory.setLibraryRootFolderID(id.asUUID());
}
}
display_startup();
do_startup_frame();
LLSD inv_lib_owner = response["inventory-lib-owner"];
if(inv_lib_owner.isDefined())
@ -1810,9 +1819,9 @@ bool idle_startup()
gInventory.setLibraryOwnerID(LLUUID(id.asUUID()));
}
}
display_startup();
do_startup_frame();
LLStartUp::setStartupState(STATE_INVENTORY_SKEL);
display_startup();
do_startup_frame();
return false;
}
@ -1831,7 +1840,7 @@ bool idle_startup()
LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL;
}
}
display_startup();
do_startup_frame();
LLSD inv_skeleton = response["inventory-skeleton"];
if (inv_skeleton.isDefined())
@ -1842,9 +1851,9 @@ bool idle_startup()
LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL;
}
}
display_startup();
do_startup_frame();
LLStartUp::setStartupState(STATE_INVENTORY_SEND2);
display_startup();
do_startup_frame();
return false;
}
@ -1890,7 +1899,7 @@ bool idle_startup()
list[agent_id] = new LLRelationship(given_rights, has_rights, false);
}
LLAvatarTracker::instance().addBuddyList(list);
display_startup();
do_startup_frame();
}
bool show_hud = false;
@ -1918,7 +1927,7 @@ bool idle_startup()
//}
}
}
display_startup();
do_startup_frame();
// Either we want to show tutorial because this is the first login
// to a Linden Help Island or the user quit with the tutorial
@ -1927,21 +1936,21 @@ bool idle_startup()
{
LLFloaterReg::showInstance("hud", LLSD(), false);
}
display_startup();
do_startup_frame();
LLSD event_notifications = response["event_notifications"];
if(event_notifications.isDefined())
{
gEventNotifier.load(event_notifications);
}
display_startup();
do_startup_frame();
LLSD classified_categories = response["classified_categories"];
if(classified_categories.isDefined())
{
LLClassifiedInfo::loadCategories(classified_categories);
}
display_startup();
do_startup_frame();
// This method MUST be called before gInventory.findCategoryUUIDForType because of
// gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap.
@ -1960,7 +1969,7 @@ bool idle_startup()
LLInventoryModelBackgroundFetch::instance().start();
gInventory.createCommonSystemCategories();
LLStartUp::setStartupState(STATE_INVENTORY_CALLBACKS );
display_startup();
do_startup_frame();
return false;
}
@ -1972,7 +1981,7 @@ bool idle_startup()
{
if (!LLInventoryModel::isSysFoldersReady())
{
display_startup();
do_startup_frame();
return false;
}
@ -1997,7 +2006,7 @@ bool idle_startup()
gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null);
gInventory.notifyObservers();
display_startup();
do_startup_frame();
// set up callbacks
LL_INFOS() << "Registering Callbacks" << LL_ENDL;
@ -2008,18 +2017,18 @@ bool idle_startup()
LLAvatarTracker::instance().registerCallbacks(msg);
LL_INFOS() << " Landmark" << LL_ENDL;
LLLandmark::registerCallbacks(msg);
display_startup();
do_startup_frame();
// request all group information
LL_INFOS() << "Requesting Agent Data" << LL_ENDL;
gAgent.sendAgentDataUpdateRequest();
display_startup();
do_startup_frame();
// Create the inventory views
LL_INFOS() << "Creating Inventory Views" << LL_ENDL;
LLFloaterReg::getInstance("inventory");
display_startup();
do_startup_frame();
LLStartUp::setStartupState( STATE_MISC );
display_startup();
do_startup_frame();
return false;
}
@ -2069,7 +2078,7 @@ bool idle_startup()
gSavedSettings.setBOOL("ShowStartLocation", true);
}
display_startup();
do_startup_frame();
// Load stored local environment if needed.
LLEnvironment::instance().loadFromSettings();
@ -2077,7 +2086,7 @@ bool idle_startup()
// *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp)
//check_merchant_status();
display_startup();
do_startup_frame();
if (gSavedSettings.getBOOL("HelpFloaterOpen"))
{
@ -2085,7 +2094,7 @@ bool idle_startup()
LLViewerHelp::instance().showTopic("");
}
display_startup();
do_startup_frame();
// We're successfully logged in.
gSavedSettings.setBOOL("FirstLoginThisInstall", false);
@ -2094,12 +2103,12 @@ bool idle_startup()
LLFloaterGridStatus::getInstance()->startGridStatusTimer();
display_startup();
do_startup_frame();
display_startup();
do_startup_frame();
// JC: Initializing audio requests many sounds for download.
init_audio();
display_startup();
do_startup_frame();
// JC: Initialize "active" gestures. This may also trigger
// many gesture downloads, if this is the user's first
@ -2137,7 +2146,7 @@ bool idle_startup()
LLGestureMgr::instance().startFetch();
}
gDisplaySwapBuffers = true;
display_startup();
do_startup_frame();
LLMessageSystem* msg = gMessageSystem;
msg->setHandlerFuncFast(_PREHASH_SoundTrigger, process_sound_trigger);
@ -2215,10 +2224,10 @@ bool idle_startup()
}
}
display_startup();
do_startup_frame();
//DEV-17797. get null folder. Any items found here moved to Lost and Found
LLInventoryModelBackgroundFetch::instance().findLostItems();
display_startup();
do_startup_frame();
LLStartUp::setStartupState( STATE_PRECACHE );
timeout.reset();
@ -2227,7 +2236,7 @@ bool idle_startup()
if (STATE_PRECACHE == LLStartUp::getStartupState())
{
display_startup();
do_startup_frame();
F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY;
// We now have an inventory skeleton, so if this is a user's first
@ -2253,7 +2262,7 @@ bool idle_startup()
callAfterCOFFetch(set_flags_and_update_appearance);
}
display_startup();
do_startup_frame();
// wait precache-delay and for agent's avatar or a lot longer.
if ((timeout_frac > 1.f) && isAgentAvatarValid())
@ -2278,7 +2287,7 @@ bool idle_startup()
set_startup_status(0.60f + 0.30f * timeout_frac,
LLTrans::getString("LoginPrecaching"),
gAgent.mMOTD.c_str());
display_startup();
do_startup_frame();
}
return true;
@ -2306,7 +2315,7 @@ bool idle_startup()
LLStartUp::setStartupState( STATE_CLEANUP );
}
display_startup();
do_startup_frame();
if (gAgent.isOutfitChosen() && (wearables_time > MAX_WEARABLES_TIME))
{
@ -2347,7 +2356,7 @@ bool idle_startup()
if (STATE_CLEANUP == LLStartUp::getStartupState())
{
set_startup_status(1.0, "", "");
display_startup();
do_startup_frame();
if (!mBenefitsSuccessfullyInit)
{
@ -2368,7 +2377,7 @@ bool idle_startup()
//gViewerWindow->revealIntroPanel();
gViewerWindow->setStartupComplete();
gViewerWindow->setProgressCancelButtonVisible(false);
display_startup();
do_startup_frame();
// We're not away from keyboard, even though login might have taken
// a while. JC
@ -2400,7 +2409,7 @@ bool idle_startup()
// LLUserAuth::getInstance()->reset();
LLStartUp::setStartupState( STATE_STARTED );
display_startup();
do_startup_frame();
// Unmute audio if desired and setup volumes.
// This is a not-uncommon crash site, so surround it with
@ -2416,7 +2425,7 @@ bool idle_startup()
LLAgentPicksInfo::getInstance()->requestNumberOfPicks();
display_startup();
do_startup_frame();
llassert(LLPathfindingManager::getInstance() != NULL);
LLPathfindingManager::getInstance()->initSystem();
@ -3021,9 +3030,7 @@ std::string LLStartUp::startupStateToString(EStartupState state)
// static
void LLStartUp::setStartupState( EStartupState state )
{
LL_INFOS("AppInit") << "Startup state changing from " <<
getStartupStateString() << " to " <<
startupStateToString(state) << LL_ENDL;
LL_INFOS("AppInit") << getStartupStateString() << " --> " << startupStateToString(state) << LL_ENDL;
getPhases().stopPhase(getStartupStateString());
gStartupState = state;
@ -3087,7 +3094,7 @@ void LLStartUp::multimediaInit()
LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL;
std::string msg = LLTrans::getString("LoginInitializingMultimedia");
set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str());
display_startup();
do_startup_frame();
}
void LLStartUp::fontInit()
@ -3095,7 +3102,7 @@ void LLStartUp::fontInit()
LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL;
std::string msg = LLTrans::getString("LoginInitializingFonts");
set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str());
display_startup();
do_startup_frame();
LLFontGL::loadDefaultFonts();
}
@ -3792,14 +3799,14 @@ bool process_login_success_response()
{
// We got an answer from the grid -> use that for map for the current session
gSavedSettings.setString("CurrentMapServerURL", map_server_url);
LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL;
LL_INFOS("LLStartUp") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL;
}
else
{
// No answer from the grid -> use the default setting for current session
map_server_url = gSavedSettings.getString("MapServerURL");
gSavedSettings.setString("CurrentMapServerURL", map_server_url);
LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL;
LL_INFOS("LLStartUp") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL;
}
// Default male and female avatars allowing the user to choose their avatar on first login.

View File

@ -642,7 +642,7 @@ void LLGLTexMemBar::draw()
text = llformat("Mesh: Reqs(Tot/Htp/Big): %u/%u/%u Rtr/Err: %u/%u Cread/Cwrite: %u/%u Low/At/High: %d/%d/%d",
LLMeshRepository::sMeshRequestCount, LLMeshRepository::sHTTPRequestCount, LLMeshRepository::sHTTPLargeRequestCount,
LLMeshRepository::sHTTPRetryCount, LLMeshRepository::sHTTPErrorCount,
LLMeshRepository::sCacheReads, LLMeshRepository::sCacheWrites,
(U32)LLMeshRepository::sCacheReads, (U32)LLMeshRepository::sCacheWrites,
LLMeshRepoThread::sRequestLowWater, LLMeshRepoThread::sRequestWaterLevel, LLMeshRepoThread::sRequestHighWater);
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*2,
text_color, LLFontGL::LEFT, LLFontGL::TOP);

View File

@ -3147,7 +3147,9 @@ void send_agent_update(bool force_send, bool send_reliable)
LL_PROFILE_ZONE_SCOPED;
llassert(!gCubeSnapshot);
if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE)
LLAgent::ETeleportState tp_state = gAgent.getTeleportState();
if (tp_state != LLAgent::TELEPORT_NONE
&& tp_state != LLAgent::TELEPORT_ARRIVING)
{
// We don't care if they want to send an agent update, they're not allowed
// until the target simulator is ready to receive them
@ -3322,7 +3324,36 @@ void send_agent_update(bool force_send, bool send_reliable)
msg->addVector3Fast(_PREHASH_CameraAtAxis, camera_at);
msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis());
msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis());
msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance);
static F32 last_draw_disatance_step = 1024;
if (tp_state == LLAgent::TELEPORT_ARRIVING || LLStartUp::getStartupState() < STATE_MISC)
{
// Inform interest list, prioritize closer area.
// Reason: currently server doesn't distance sort attachments, by restricting range
// we reduce the number of attachments sent to the viewer, thus prioritizing
// closer ones.
// Todo: revise and remove once server gets distance sorting.
last_draw_disatance_step = llmax((F32)(gAgentCamera.mDrawDistance / 2.f), 50.f);
msg->addF32Fast(_PREHASH_Far, last_draw_disatance_step);
}
else if (last_draw_disatance_step < gAgentCamera.mDrawDistance)
{
static LLFrameTimer last_step_time;
if (last_step_time.getElapsedTimeF32() > 1.f)
{
// gradually increase draw distance
// Idealy this should be not per second, but based on how loaded
// mesh thread is, but hopefully this is temporary.
last_step_time.reset();
F32 step = gAgentCamera.mDrawDistance * 0.1f;
last_draw_disatance_step = llmin(last_draw_disatance_step + step, gAgentCamera.mDrawDistance);
}
msg->addF32Fast(_PREHASH_Far, last_draw_disatance_step);
}
else
{
msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance);
}
msg->addU32Fast(_PREHASH_ControlFlags, control_flags);

View File

@ -30,6 +30,7 @@
#include "llviewertexturelist.h"
#include "llagent.h"
#include "llgl.h" // fot gathering stats from GL
#include "llimagegl.h"
#include "llimagebmp.h"
@ -815,10 +816,19 @@ void LLViewerTextureList::updateImages(F32 max_time)
clearFetchingRequests();
gPipeline.clearRebuildGroups();
cleared = true;
return;
}
// ARRIVING is a delay to let things decode, cache and process,
// so process textures like normal despite gTeleportDisplay
if (gAgent.getTeleportState() != LLAgent::TELEPORT_ARRIVING)
{
return;
}
return;
}
cleared = false;
else
{
cleared = false;
}
LLAppViewer::getTextureFetch()->setTextureBandwidth((F32)LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::TEXTURE_NETWORK_DATA_RECEIVED).value());

View File

@ -682,7 +682,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mFullyLoaded(false),
mPreviousFullyLoaded(false),
mFullyLoadedInitialized(false),
mLastCloudAttachmentCount(0),
mLastCloudAttachmentCount(-1),
mVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN),
mLoadedCallbacksPaused(false),
mLoadedCallbackTextures(0),
@ -2794,7 +2794,10 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
}
// attach objects that were waiting for a drawable
lazyAttach();
if (!mPendingAttachment.empty())
{
lazyAttach();
}
// animate the character
// store off last frame's root position to be consistent with camera position
@ -3226,6 +3229,7 @@ void LLVOAvatar::idleUpdateLoadingEffect()
if (mFirstFullyVisible)
{
mFirstFullyVisible = false;
mLastCloudAttachmentCount = (S32)mSimAttachments.size();
mFirstDecloudTime = mFirstAppearanceMessageTimer.getElapsedTimeF32();
if (isSelf())
{
@ -7710,6 +7714,64 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )
}
}
bool check_object_for_mesh_loading(LLViewerObject* objectp)
{
if (!objectp || !objectp->getVolume())
{
return false;
}
LLVolume* volp = objectp->getVolume();
const LLUUID& mesh_id = volp->getParams().getSculptID();
if (mesh_id.isNull())
{
// No mesh nor skin info needed
return false;
}
if (volp->isMeshAssetUnavaliable())
{
// Mesh failed to load, do not expect it
return false;
}
if (!objectp->mDrawable)
{
return false;
}
LLVOVolume* pvobj = objectp->mDrawable->getVOVolume();
if (pvobj)
{
if (!pvobj->isMesh())
{
// Not a mesh
return false;
}
if (!volp->isMeshAssetLoaded())
{
// Waiting for mesh
return true;
}
const LLMeshSkinInfo* skin_data = pvobj->getSkinInfo();
if (skin_data)
{
// Skin info present, done
return false;
}
if (pvobj->isSkinInfoUnavaliable())
{
// Load failed or info not present, don't expect it
return false;
}
}
// object is not ready
return true;
}
bool LLVOAvatar::hasPendingAttachedMeshes()
{
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
@ -7724,62 +7786,20 @@ bool LLVOAvatar::hasPendingAttachedMeshes()
++attachment_iter)
{
LLViewerObject* objectp = attachment_iter->get();
if (objectp)
if (objectp && !objectp->isDead())
{
if (check_object_for_mesh_loading(objectp))
{
return true;
}
LLViewerObject::const_child_list_t& child_list = objectp->getChildren();
for (LLViewerObject::child_list_t::const_iterator iter1 = child_list.begin();
iter1 != child_list.end(); ++iter1)
{
LLViewerObject* objectchild = *iter1;
if (objectchild && objectchild->getVolume())
if (check_object_for_mesh_loading(objectchild))
{
const LLUUID& mesh_id = objectchild->getVolume()->getParams().getSculptID();
if (mesh_id.isNull())
{
// No mesh nor skin info needed
continue;
}
if (objectchild->getVolume()->isMeshAssetUnavaliable())
{
// Mesh failed to load, do not expect it
continue;
}
if (objectchild->mDrawable)
{
LLVOVolume* pvobj = objectchild->mDrawable->getVOVolume();
if (pvobj)
{
if (!pvobj->isMesh())
{
// Not a mesh
continue;
}
if (!objectchild->getVolume()->isMeshAssetLoaded())
{
// Waiting for mesh
return true;
}
const LLMeshSkinInfo* skin_data = pvobj->getSkinInfo();
if (skin_data)
{
// Skin info present, done
continue;
}
if (pvobj->isSkinInfoUnavaliable())
{
// Load failed or info not present, don't expect it
continue;
}
}
// objectchild is not ready
return true;
}
return true;
}
}
}
@ -8382,7 +8402,7 @@ bool LLVOAvatar::updateIsFullyLoaded()
);
// compare amount of attachments to one reported by simulator
if (!loading && !isSelf() && rez_status < 4 && mLastCloudAttachmentCount < mSimAttachments.size())
if (!isSelf() && mLastCloudAttachmentCount < mSimAttachments.size() && mSimAttachments.size() > 0)
{
S32 attachment_count = getAttachmentCount();
if (mLastCloudAttachmentCount != attachment_count)
@ -8400,6 +8420,11 @@ bool LLVOAvatar::updateIsFullyLoaded()
// waiting
loading = true;
}
else if (!loading)
{
// for hasFirstFullAttachmentData
mLastCloudAttachmentCount = (S32)mSimAttachments.size();
}
}
}
updateRezzedStatusTimers(rez_status);
@ -8513,6 +8538,12 @@ bool LLVOAvatar::isFullyLoaded() const
return (mRenderUnloadedAvatar || mFullyLoaded);
}
bool LLVOAvatar::hasFirstFullAttachmentData() const
{
return !mFirstFullyVisible // Avatar is fully visible, have all data
|| mLastCloudAttachmentCount >= (S32)mSimAttachments.size();
}
bool LLVOAvatar::isTooComplex() const
{
bool too_complex;

View File

@ -385,6 +385,7 @@ public:
//--------------------------------------------------------------------
public:
bool isFullyLoaded() const;
bool hasFirstFullAttachmentData() const;
F32 getFirstDecloudTime() const {return mFirstDecloudTime;}
// check and return current state relative to limits