Moar Thickbrick!

This commit is contained in:
Siana Gearz
2010-11-18 22:43:00 +01:00
parent e9296374cf
commit 923c18bc0a
3 changed files with 132 additions and 37 deletions

View File

@@ -61,6 +61,8 @@
using namespace LLVOAvatarDefines; using namespace LLVOAvatarDefines;
const S32 MAX_BAKE_UPLOAD_ATTEMPTS = 4;
// static // static
S32 LLTexLayerSetBuffer::sGLByteCount = 0; S32 LLTexLayerSetBuffer::sGLByteCount = 0;
@@ -98,6 +100,8 @@ LLTexLayerSetBuffer::LLTexLayerSetBuffer(LLTexLayerSet* owner, S32 width, S32 he
mNeedsUpdate( TRUE ), mNeedsUpdate( TRUE ),
mNeedsUpload( FALSE ), mNeedsUpload( FALSE ),
mUploadPending( FALSE ), // Not used for any logic here, just to sync sending of updates mUploadPending( FALSE ), // Not used for any logic here, just to sync sending of updates
mUploadFailCount( 0 ),
mUploadAfter( 0 ),
mTexLayerSet( owner ) mTexLayerSet( owner )
{ {
LLTexLayerSetBuffer::sGLByteCount += getSize(); LLTexLayerSetBuffer::sGLByteCount += getSize();
@@ -151,6 +155,18 @@ void LLTexLayerSetBuffer::requestUpload()
{ {
mNeedsUpload = TRUE; mNeedsUpload = TRUE;
mUploadPending = TRUE; mUploadPending = TRUE;
mUploadAfter = 0;
}
}
// request an upload to start delay_usec microseconds from now
void LLTexLayerSetBuffer::requestDelayedUpload(U64 delay_usec)
{
if (!mNeedsUpload)
{
mNeedsUpload = TRUE;
mUploadPending = TRUE;
mUploadAfter = LLFrameTimer::getTotalTime() + delay_usec;
} }
} }
@@ -161,6 +177,14 @@ void LLTexLayerSetBuffer::cancelUpload()
mNeedsUpload = FALSE; mNeedsUpload = FALSE;
} }
mUploadPending = FALSE; mUploadPending = FALSE;
mUploadAfter = 0;
}
// do we need to upload, and do we have sufficient data to create an uploadable composite?
BOOL LLTexLayerSetBuffer::needsUploadNow() const
{
BOOL upload = mNeedsUpload && mTexLayerSet->isLocalTextureDataFinal() && (gAgent.mNumPendingQueries == 0);
return (upload && (LLFrameTimer::getTotalTime() > mUploadAfter));
} }
void LLTexLayerSetBuffer::pushProjection() void LLTexLayerSetBuffer::pushProjection()
@@ -187,7 +211,7 @@ void LLTexLayerSetBuffer::popProjection()
BOOL LLTexLayerSetBuffer::needsRender() BOOL LLTexLayerSetBuffer::needsRender()
{ {
LLVOAvatar* avatar = mTexLayerSet->getAvatar(); LLVOAvatar* avatar = mTexLayerSet->getAvatar();
BOOL upload_now = mNeedsUpload && mTexLayerSet->isLocalTextureDataFinal() && gAgent.mNumPendingQueries == 0; BOOL upload_now = needsUploadNow();
BOOL needs_update = (mNeedsUpdate || upload_now) && !avatar->mAppearanceAnimating; BOOL needs_update = (mNeedsUpdate || upload_now) && !avatar->mAppearanceAnimating;
if (needs_update) if (needs_update)
{ {
@@ -231,7 +255,7 @@ BOOL LLTexLayerSetBuffer::render()
// do we need to upload, and do we have sufficient data to create an uploadable composite? // do we need to upload, and do we have sufficient data to create an uploadable composite?
// When do we upload the texture if gAgent.mNumPendingQueries is non-zero? // When do we upload the texture if gAgent.mNumPendingQueries is non-zero?
BOOL upload_now = (gAgent.mNumPendingQueries == 0 && mNeedsUpload && mTexLayerSet->isLocalTextureDataFinal()); BOOL upload_now = needsUploadNow();
BOOL success = TRUE; BOOL success = TRUE;
// Composite the color data // Composite the color data
@@ -434,12 +458,13 @@ void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, void* user
LLVOAvatar* avatar = gAgent.getAvatarObject(); LLVOAvatar* avatar = gAgent.getAvatarObject();
if (0 == result && if (avatar && !avatar->isDead() && baked_upload_data &&
avatar && !avatar->isDead() &&
baked_upload_data->mAvatar == avatar && // Sanity check: only the user's avatar should be uploading textures. baked_upload_data->mAvatar == avatar && // Sanity check: only the user's avatar should be uploading textures.
baked_upload_data->mLayerSet->hasComposite()) baked_upload_data->mLayerSet->hasComposite())
{ {
LLTexLayerSetBuffer* layerset_buffer = baked_upload_data->mLayerSet->getComposite(); LLTexLayerSetBuffer* layerset_buffer = baked_upload_data->mLayerSet->getComposite();
S32 failures = layerset_buffer->mUploadFailCount;
layerset_buffer->mUploadFailCount = 0;
if (layerset_buffer->mUploadID.isNull()) if (layerset_buffer->mUploadID.isNull())
{ {
@@ -467,9 +492,20 @@ void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, void* user
} }
else else
{ {
// Avatar appearance is changing, ignore the upload results ++failures;
llinfos << "Baked upload failed. Reason: " << result << llendl; llinfos << "Baked upload failed (attempt " << failures << "/" << MAX_BAKE_UPLOAD_ATTEMPTS << "), ";
// *FIX: retry upload after n seconds, asset server could be busy if (failures >= MAX_BAKE_UPLOAD_ATTEMPTS)
{
llcont << "giving up.";
}
else
{
const F32 delay = 5.f;
llcont << llformat("retrying in %.2f seconds.", delay);
layerset_buffer->mUploadFailCount = failures;
layerset_buffer->requestDelayedUpload((U64)(delay * 1000000));
}
llcont << llendl;
} }
} }
else else

View File

@@ -218,6 +218,7 @@ public:
BOOL needsRender(); BOOL needsRender();
void requestUpdate(); void requestUpdate();
void requestUpload(); void requestUpload();
void requestDelayedUpload(U64 delay_usec);
void cancelUpload(); void cancelUpload();
BOOL uploadPending() { return mUploadPending; } BOOL uploadPending() { return mUploadPending; }
BOOL render( S32 x, S32 y, S32 width, S32 height ); BOOL render( S32 x, S32 y, S32 width, S32 height );
@@ -234,12 +235,15 @@ public:
private: private:
void pushProjection(); void pushProjection();
void popProjection(); void popProjection();
BOOL needsUploadNow() const;
private: private:
BOOL mNeedsUpdate; BOOL mNeedsUpdate;
BOOL mNeedsUpload; BOOL mNeedsUpload;
BOOL mUploadPending; BOOL mUploadPending;
LLUUID mUploadID; // Identifys the current upload process (null if none). Used to avoid overlaps (eg, when the user rapidly makes two changes outside of Face Edit) LLUUID mUploadID; // Identifys the current upload process (null if none). Used to avoid overlaps (eg, when the user rapidly makes two changes outside of Face Edit)
S32 mUploadFailCount;
U64 mUploadAfter; // delay upload until after this time (in microseconds)
LLTexLayerSet* mTexLayerSet; LLTexLayerSet* mTexLayerSet;
static S32 sGLByteCount; static S32 sGLByteCount;

View File

@@ -156,7 +156,7 @@ public:
void callbackHttpGet(const LLChannelDescriptors& channels, void callbackHttpGet(const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer, const LLIOPipe::buffer_ptr_t& buffer,
bool last_block, bool success); bool partial, bool unsatisfiable, bool success);
void callbackCacheRead(bool success, LLImageFormatted* image, void callbackCacheRead(bool success, LLImageFormatted* image,
S32 imagesize, BOOL islocal); S32 imagesize, BOOL islocal);
void callbackCacheWrite(bool success); void callbackCacheWrite(bool success);
@@ -175,7 +175,7 @@ protected:
LLTextureFetchWorker(LLTextureFetch* fetcher, const LLUUID& id, const LLHost& host, LLTextureFetchWorker(LLTextureFetch* fetcher, const LLUUID& id, const LLHost& host,
F32 priority, S32 discard, S32 size); F32 priority, S32 discard, S32 size);
LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host, LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host,
F32 priority, S32 discard, S32 size); F32 priority, S32 discard, S32 size, bool can_use_http);
private: private:
/*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD) /*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD)
@@ -323,6 +323,7 @@ public:
{ {
bool success = false; bool success = false;
bool partial = false; bool partial = false;
bool unsatisfiable = false;
if (200 <= status && status < 300) if (200 <= status && status < 300)
{ {
success = true; success = true;
@@ -331,10 +332,10 @@ public:
partial = true; partial = true;
} }
} }
else else if (status == HTTP_REQUESTED_RANGE_NOT_SATISFIABLE)
{ {
worker->setGetStatus(status, reason); llwarns << "TextureFetch: Request was an unsatisfiable range: mRequestedSize=" << mRequestedSize << " mOffset=" << mOffset << " for: " << mID << LL_ENDL;
// llwarns << status << ": " << reason << llendl; unsatisfiable = true;
} }
if (!success) if (!success)
{ {
@@ -342,7 +343,7 @@ public:
// llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl; // llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl;
} }
mFetcher->removeFromHTTPQueue(mID); mFetcher->removeFromHTTPQueue(mID);
worker->callbackHttpGet(channels, buffer, partial, success); worker->callbackHttpGet(channels, buffer, partial, unsatisfiable, success);
} }
else else
{ {
@@ -387,7 +388,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
const LLHost& host, // Simulator host const LLHost& host, // Simulator host
F32 priority, // Priority F32 priority, // Priority
S32 discard, // Desired discard S32 discard, // Desired discard
S32 size) // Desired size S32 size, // Desired size
bool can_use_http) // Try HTTP first
: LLWorkerClass(fetcher, "TextureFetch"), : LLWorkerClass(fetcher, "TextureFetch"),
mState(INIT), mState(INIT),
mWriteToCacheState(NOT_WRITE), mWriteToCacheState(NOT_WRITE),
@@ -419,7 +421,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
mNeedsAux(FALSE), mNeedsAux(FALSE),
mHaveAllData(FALSE), mHaveAllData(FALSE),
mInLocalCache(FALSE), mInLocalCache(FALSE),
mCanUseHTTP(true), mCanUseHTTP(can_use_http),
mHTTPFailCount(0), mHTTPFailCount(0),
mRetryAttempt(0), mRetryAttempt(0),
mActiveCount(0), mActiveCount(0),
@@ -869,6 +871,13 @@ bool LLTextureFetchWorker::doWork(S32 param)
if (mFormattedImage.notNull()) if (mFormattedImage.notNull())
{ {
cur_size = mFormattedImage->getDataSize(); // amount of data we already have cur_size = mFormattedImage->getDataSize(); // amount of data we already have
if (mFormattedImage->getDiscardLevel() == 0)
{
// We already have all the data, just decode it
mLoadedDiscard = mFormattedImage->getDiscardLevel();
mState = DECODE_IMAGE;
return false;
}
} }
mRequestedSize = mDesiredSize; mRequestedSize = mDesiredSize;
mRequestedDiscard = mDesiredDiscard; mRequestedDiscard = mDesiredDiscard;
@@ -885,6 +894,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
mGetReason.clear(); mGetReason.clear();
lldebugs << "HTTP GET: " << mID << " Offset: " << offset lldebugs << "HTTP GET: " << mID << " Offset: " << offset
<< " Bytes: " << mRequestedSize << " Bytes: " << mRequestedSize
<< " Range: " << offset << "-" << offset+mRequestedSize-1
<< " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << max_bandwidth << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << max_bandwidth
<< llendl; << llendl;
setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
@@ -1152,8 +1162,8 @@ bool LLTextureFetchWorker::doWork(S32 param)
if(mDecodedDiscard<=0) if(mDecodedDiscard<=0)
{ {
return true; return true;
} }
else else
{ {
return false; return false;
@@ -1305,7 +1315,9 @@ bool LLTextureFetchWorker::processSimulatorPackets()
void LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, void LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer, const LLIOPipe::buffer_ptr_t& buffer,
bool last_block, bool success) bool partial,
bool unsatisfiable,
bool success)
{ {
LLMutexLock lock(&mWorkMutex); LLMutexLock lock(&mWorkMutex);
@@ -1320,46 +1332,89 @@ void LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
llwarns << "Duplicate callback for " << mID.asString() << llendl; llwarns << "Duplicate callback for " << mID.asString() << llendl;
return; // ignore duplicate callback return; // ignore duplicate callback
} }
S32 data_size = 0;
if (success) if (success)
{ {
// get length of stream: // get length of stream:
S32 data_size = buffer->countAfter(channels.in(), NULL); data_size = buffer->countAfter(channels.in(), NULL);
gImageList.sTextureBits += data_size * 8; // Approximate - does not include header bits gImageList.sTextureBits += data_size * 8; // Approximate - does not include header bits
//llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl; //llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl;
if (data_size > 0) if (data_size > 0)
{ {
// *TODO: set the formatted image data here directly to avoid the copy bool clean_data = false;
mBuffer = new U8[data_size]; bool done = false;
buffer->readAfter(channels.in(), NULL, mBuffer, data_size); if (!partial)
mBufferSize += data_size; {
if (data_size < mRequestedSize || last_block == true) // we got the whole image in one go
done = true;
clean_data = true;
}
else if (data_size < mRequestedSize)
{ {
mHaveAllData = TRUE; // we have the whole image
done = true;
}
else if (data_size == mRequestedSize)
{
if (mRequestedDiscard <= 0)
{
done = true;
}
else
{
// this is the normal case where we get the data we requested,
// but still need to request more data.
}
} }
else if (data_size > mRequestedSize) else if (data_size > mRequestedSize)
{ {
// *TODO: This shouldn't be happening any more // *TODO: This shouldn't be happening any more
llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl; llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl;
mHaveAllData = TRUE; done = true;
clean_data = true;
llassert_always(mDecodeHandle == 0); llassert_always(mDecodeHandle == 0);
mFormattedImage = NULL; // discard any previous data we had
mBufferSize = data_size;
} }
if (clean_data)
{
resetFormattedData(); // discard any previous data we had
llassert(mBufferSize == 0);
}
if (done)
{
mHaveAllData = TRUE;
mRequestedDiscard = 0;
}
// *TODO: set the formatted image data here directly to avoid the copy
mBuffer = new U8[data_size];
buffer->readAfter(channels.in(), NULL, mBuffer, data_size);
mBufferSize += data_size;
mRequestedSize = data_size;
} }
else
{
// We requested data but received none (and no error),
// so presumably we have all of it
mHaveAllData = TRUE;
}
mRequestedSize = data_size;
} }
else else
{ {
mRequestedSize = -1; // error mRequestedSize = -1; // error
} }
if ((success && (data_size == 0)) || unsatisfiable)
{
if (mFormattedImage.notNull() && mFormattedImage->getDataSize() > 0)
{
// we already have some data, so we'll assume we have it all
mRequestedSize = 0;
mRequestedDiscard = 0;
mHaveAllData = TRUE;
}
else
{
mRequestedSize = -1; // treat this fetch as if it failed.
}
}
mLoaded = TRUE; mLoaded = TRUE;
setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
} }
@@ -1563,7 +1618,7 @@ bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, con
worker->lockWorkMutex(); worker->lockWorkMutex();
worker->setImagePriority(priority); worker->setImagePriority(priority);
worker->setDesiredDiscard(desired_discard, desired_size); worker->setDesiredDiscard(desired_discard, desired_size);
worker->setCanUseHTTP(can_use_http) ; worker->setCanUseHTTP(can_use_http);
worker->unlockWorkMutex(); worker->unlockWorkMutex();
if (!worker->haveWork()) if (!worker->haveWork())
{ {
@@ -1579,7 +1634,7 @@ bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, con
} }
else else
{ {
worker = new LLTextureFetchWorker(this, url, id, host, priority, desired_discard, desired_size); worker = new LLTextureFetchWorker(this, url, id, host, priority, desired_discard, desired_size, can_use_http);
mRequestMap[id] = worker; mRequestMap[id] = worker;
} }
worker->mActiveCount++; worker->mActiveCount++;