EXT-8135 FIXED Textures blurry when in Appearance Edit mode

EXT-8445 Reduce baked texture timeout fro 120sec to 60sec default

Also did some minor infrastructure cleanup, added code comments, etc.  There is now separate logic for determining how to handle update (versus upload) requests.
Also made a trivial change to llvoavatar to properly encapsulate mAppearanceAnimating.
Also reduced the baked texture timeout to 60s (in settings.xml)
meow-7.2.2
Loren Shih 2010-07-15 17:24:12 -04:00
parent 6ce6ce238c
commit 020b156299
7 changed files with 183 additions and 70 deletions

View File

@ -585,7 +585,7 @@
<key>Value</key>
<integer>2</integer>
</map>
<key>AvatarBakedTextureTimeout</key>
<key>AvatarBakedTextureUploadTimeout</key>
<map>
<key>Comment</key>
<string>Specifes the maximum time in seconds to wait before sending your baked textures for avatar appearance. Set to 0 to disable and wait until all baked textures are at highest resolution.</string>
@ -594,8 +594,20 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>120</integer>
<integer>60</integer>
</map>
<key>AvatarBakedLocalTextureUpdateTimeout</key>
<map>
<key>Comment</key>
<string>Specifes the maximum time in seconds to wait before updating your appearance during appearance mode.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>10</integer>
</map>
<key>AvatarSex</key>
<map>
<key>Comment</key>

View File

@ -119,14 +119,16 @@ LLTexLayerSetBuffer::LLTexLayerSetBuffer(LLTexLayerSet* const owner,
S32 width, S32 height) :
// ORDER_LAST => must render these after the hints are created.
LLViewerDynamicTexture( width, height, 4, LLViewerDynamicTexture::ORDER_LAST, TRUE ),
mNeedsUpdate(TRUE),
mNeedsUpload(FALSE),
mUploadPending(FALSE), // Not used for any logic here, just to sync sending of updates
mNeedsUpload(FALSE),
mNumLowresUploads(0),
mNeedsUpdate(TRUE),
mNumLowresUpdates(0),
mTexLayerSet(owner)
{
LLTexLayerSetBuffer::sGLByteCount += getSize();
mNeedsUploadTimer.start();
mNeedsUpdateTimer.start();
}
LLTexLayerSetBuffer::~LLTexLayerSetBuffer()
@ -165,8 +167,9 @@ void LLTexLayerSetBuffer::dumpTotalByteCount()
void LLTexLayerSetBuffer::requestUpdate()
{
conditionalRestartUploadTimer();
restartUpdateTimer();
mNeedsUpdate = TRUE;
mNumLowresUpdates = 0;
// If we're in the middle of uploading a baked texture, we don't care about it any more.
// When it's downloaded, ignore it.
mUploadID.setNull();
@ -196,6 +199,12 @@ void LLTexLayerSetBuffer::conditionalRestartUploadTimer()
}
}
void LLTexLayerSetBuffer::restartUpdateTimer()
{
mNeedsUpdateTimer.reset();
mNeedsUpdateTimer.start();
}
void LLTexLayerSetBuffer::cancelUpload()
{
mNeedsUpload = FALSE;
@ -229,25 +238,31 @@ BOOL LLTexLayerSetBuffer::needsRender()
llassert(mTexLayerSet->getAvatar() == gAgentAvatarp);
if (!isAgentAvatarValid()) return FALSE;
const BOOL upload_now = isReadyToUpload();
BOOL needs_update = (mNeedsUpdate || upload_now) && !gAgentAvatarp->mAppearanceAnimating;
if (needs_update)
const BOOL upload_now = mNeedsUpload && isReadyToUpload();
const BOOL update_now = mNeedsUpdate && isReadyToUpdate();
// Don't render if we don't want to (or aren't ready to) upload or update.
if (!(update_now || upload_now))
{
BOOL invalid_skirt = gAgentAvatarp->getBakedTE(mTexLayerSet) == LLVOAvatarDefines::TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT);
if (invalid_skirt)
{
// we were trying to create a skirt texture
// but we're no longer wearing a skirt...
needs_update = FALSE;
cancelUpload();
}
else
{
needs_update &= mTexLayerSet->isLocalTextureDataAvailable();
}
return FALSE;
}
return needs_update;
// Don't render if we're animating our appearance.
if (gAgentAvatarp->getIsAppearanceAnimating())
{
return FALSE;
}
// Don't render if we are trying to create a shirt texture but aren't wearing a skirt.
if (gAgentAvatarp->getBakedTE(mTexLayerSet) == LLVOAvatarDefines::TEX_SKIRT_BAKED &&
!gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT))
{
cancelUpload();
return FALSE;
}
// Render if we have at least minimal level of detail for each local texture.
return mTexLayerSet->isLocalTextureDataAvailable();
}
void LLTexLayerSetBuffer::preRender(BOOL clear_depth)
@ -272,11 +287,12 @@ BOOL LLTexLayerSetBuffer::render()
gGL.setColorMask(true, true);
// 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?
const BOOL upload_now = isReadyToUpload();
// TODO: When do we upload the texture if gAgent.mNumPendingQueries is non-zero?
const BOOL upload_now = mNeedsUpload && isReadyToUpload();
const BOOL update_now = mNeedsUpdate && isReadyToUpdate();
BOOL success = TRUE;
// Composite the color data
LLGLSUIDefault gls_ui;
success &= mTexLayerSet->render( mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight );
@ -294,7 +310,7 @@ BOOL LLTexLayerSetBuffer::render()
if (mTexLayerSet->isVisible())
{
mTexLayerSet->getAvatar()->debugBakedTextureUpload(mTexLayerSet->getBakedTexIndex(), FALSE); // FALSE for start of upload, TRUE for finish.
readBackAndUpload();
doUpload();
}
else
{
@ -305,6 +321,11 @@ BOOL LLTexLayerSetBuffer::render()
}
}
}
if (update_now)
{
doUpdate();
}
// reset GL state
gGL.setColorMask(true, true);
@ -312,7 +333,6 @@ BOOL LLTexLayerSetBuffer::render()
// we have valid texture data now
mGLTexturep->setGLTextureCreated(true);
mNeedsUpdate = FALSE;
return success;
}
@ -339,16 +359,16 @@ BOOL LLTexLayerSetBuffer::uploadInProgress() const
BOOL LLTexLayerSetBuffer::isReadyToUpload() const
{
if (!mNeedsUpload) return FALSE; // Don't need to upload if we haven't requested one.
if (!gAgentQueryManager.hasNoPendingQueries()) return FALSE; // Can't upload if there are pending queries.
if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures()) return FALSE; // Don't upload if avatar is using composites.
// If we requested an upload and have the final LOD ready, then upload.
const BOOL can_highest_lod = mTexLayerSet->isLocalTextureDataFinal();
if (can_highest_lod) return TRUE;
if (mTexLayerSet->isLocalTextureDataFinal()) return TRUE;
const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureTimeout");
if (texture_timeout)
// Upload if we've hit a timeout. Upload is a pretty expensive process so we need to make sure
// we aren't doing uploads too frequently.
const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureUploadTimeout");
if (texture_timeout != 0)
{
// The timeout period increases exponentially between every lowres upload in order to prevent
// spamming the server with frequent uploads.
@ -359,10 +379,33 @@ BOOL LLTexLayerSetBuffer::isReadyToUpload() const
const BOOL has_lower_lod = mTexLayerSet->isLocalTextureDataAvailable();
if (has_lower_lod && is_upload_textures_timeout) return TRUE;
}
return FALSE;
}
BOOL LLTexLayerSetBuffer::updateImmediate()
BOOL LLTexLayerSetBuffer::isReadyToUpdate() const
{
// If we requested an update and have the final LOD ready, then update.
if (mTexLayerSet->isLocalTextureDataFinal()) return TRUE;
// If we haven't done an update yet, then just do one now regardless of state of textures.
if (mNumLowresUpdates == 0) return TRUE;
// Update if we've hit a timeout. Unlike for uploads, we can make this timeout fairly small
// since render unnecessarily doesn't cost much.
const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedLocalTextureUpdateTimeout");
if (texture_timeout != 0)
{
// If we hit our timeout and have textures available at even lower resolution, then update.
const BOOL is_update_textures_timeout = mNeedsUpdateTimer.getElapsedTimeF32() >= texture_timeout;
const BOOL has_lower_lod = mTexLayerSet->isLocalTextureDataAvailable();
if (has_lower_lod && is_update_textures_timeout) return TRUE;
}
return FALSE;
}
BOOL LLTexLayerSetBuffer::requestUpdateImmediate()
{
mNeedsUpdate = TRUE;
BOOL result = FALSE;
@ -377,7 +420,9 @@ BOOL LLTexLayerSetBuffer::updateImmediate()
return result;
}
void LLTexLayerSetBuffer::readBackAndUpload()
// Create the baked texture, send it out to the server, then wait for it to come
// back so we can switch to using it.
void LLTexLayerSetBuffer::doUpload()
{
llinfos << "Uploading baked " << mTexLayerSet->getBodyRegionName() << llendl;
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_BAKES);
@ -447,6 +492,7 @@ void LLTexLayerSetBuffer::readBackAndUpload()
LLBakedUploadData* baked_upload_data = new LLBakedUploadData(gAgentAvatarp,
this->mTexLayerSet,
asset_id);
// upload ID is used to avoid overlaps, e.g. when the user rapidly makes two changes outside of Face Edit.
mUploadID = asset_id;
// Upload the image
@ -493,9 +539,10 @@ void LLTexLayerSetBuffer::readBackAndUpload()
std::string lod_str = highest_lod ? "HighRes" : "LowRes";
LLSD args;
args["EXISTENCE"] = llformat("%d",(U32)mTexLayerSet->getAvatar()->debugGetExistenceTimeElapsedF32());
args["TIME"] = llformat("%d",(U32)mNeedsUploadTimer.getElapsedTimeF32());
args["TIME"] = llformat("%d",(U32)mNeedsUpdateTimer.getElapsedTimeF32());
args["BODYREGION"] = mTexLayerSet->getBodyRegionName();
args["RESOLUTION"] = lod_str;
args["ACTION"] = "uploaded";
LLNotificationsUtil::add("AvatarRezSelfBakeNotification",args);
llinfos << "Uploading [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << llendl;
}
@ -520,6 +567,37 @@ void LLTexLayerSetBuffer::readBackAndUpload()
delete [] baked_color_data;
}
// Mostly bookkeeping; don't need to actually "do" anything since
// render() will actually do the update.
void LLTexLayerSetBuffer::doUpdate()
{
const BOOL highest_lod = mTexLayerSet->isLocalTextureDataFinal();
if (highest_lod)
{
mNeedsUpdate = FALSE;
}
else
{
mNumLowresUpdates++;
}
restartUpdateTimer();
// Print out notification that we uploaded this texture.
if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
{
const BOOL highest_lod = mTexLayerSet->isLocalTextureDataFinal();
std::string lod_str = highest_lod ? "HighRes" : "LowRes";
LLSD args;
args["EXISTENCE"] = llformat("%d",(U32)mTexLayerSet->getAvatar()->debugGetExistenceTimeElapsedF32());
args["TIME"] = llformat("%d",(U32)mNeedsUploadTimer.getElapsedTimeF32());
args["BODYREGION"] = mTexLayerSet->getBodyRegionName();
args["RESOLUTION"] = lod_str;
args["ACTION"] = "locally updated";
LLNotificationsUtil::add("AvatarRezSelfBakeNotification",args);
llinfos << "Locally updating [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUpdateTimer.getElapsedTimeF32() << " ]" << llendl;
}
}
// static
void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid,
@ -931,7 +1009,7 @@ void LLTexLayerSet::setUpdatesEnabled( BOOL b )
void LLTexLayerSet::updateComposite()
{
createComposite();
mComposite->updateImmediate();
mComposite->requestUpdateImmediate();
}
LLTexLayerSetBuffer* LLTexLayerSet::getComposite()

View File

@ -270,47 +270,69 @@ class LLTexLayerSetBuffer : public LLViewerDynamicTexture
public:
LLTexLayerSetBuffer(LLTexLayerSet* const owner, S32 width, S32 height);
virtual ~LLTexLayerSetBuffer();
public:
/*virtual*/ S8 getType() const;
virtual void preRender(BOOL clear_depth);
virtual void postRender(BOOL success);
virtual BOOL render();
BOOL updateImmediate();
BOOL isInitialized(void) const;
BOOL uploadPending() const; // We are expecting a new texture to be uploaded at some point
BOOL uploadNeeded() const; // We need to upload a new texture
BOOL uploadInProgress() const; // We have started uploading a new texture and are awaiting the result
/*virtual*/ BOOL needsRender();
void requestUpdate();
void requestUpload();
void cancelUpload();
BOOL render(S32 x, S32 y, S32 width, S32 height);
void readBackAndUpload();
static void onTextureUploadComplete(const LLUUID& uuid,
void* userdata,
S32 result, LLExtStat ext_status);
static void dumpTotalByteCount();
const std::string dumpTextureInfo() const;
virtual void restoreGLTexture();
virtual void destroyGLTexture();
protected:
void pushProjection() const;
void popProjection() const;
BOOL isReadyToUpload() const;
void conditionalRestartUploadTimer();
private:
LLTexLayerSet* const mTexLayerSet;
BOOL mNeedsUpdate; // whether we need to update our baked textures
BOOL mNeedsUpload; // whether we need to send our baked textures to the server
U32 mNumLowresUploads; // number of times we've sent a lowres version of our baked textures to the server
BOOL mUploadPending; // whether we have received back the new baked textures
LLUUID mUploadID; // the current upload process (null if none). Used to avoid overlaps, e.g. when the user rapidly makes two changes outside of Face Edit.
static S32 sGLByteCount;
LLFrameTimer mNeedsUploadTimer; // Tracks time since upload was requested
//--------------------------------------------------------------------
// Render
//--------------------------------------------------------------------
public:
/*virtual*/ BOOL needsRender();
protected:
BOOL render(S32 x, S32 y, S32 width, S32 height);
virtual void preRender(BOOL clear_depth);
virtual void postRender(BOOL success);
virtual BOOL render();
//--------------------------------------------------------------------
// Uploads
//--------------------------------------------------------------------
public:
void requestUpload();
void cancelUpload();
BOOL uploadNeeded() const; // We need to upload a new texture
BOOL uploadInProgress() const; // We have started uploading a new texture and are awaiting the result
BOOL uploadPending() const; // We are expecting a new texture to be uploaded at some point
static void onTextureUploadComplete(const LLUUID& uuid,
void* userdata,
S32 result, LLExtStat ext_status);
protected:
BOOL isReadyToUpload() const;
void doUpload(); // Does a read back and upload.
void conditionalRestartUploadTimer();
private:
BOOL mNeedsUpload; // Whether we need to send our baked textures to the server
U32 mNumLowresUploads; // Number of times we've sent a lowres version of our baked textures to the server
BOOL mUploadPending; // Whether we have received back the new baked textures
LLUUID mUploadID; // The current upload process (null if none).
LLFrameTimer mNeedsUploadTimer; // Tracks time since upload was requested and performed.
//--------------------------------------------------------------------
// Updates
//--------------------------------------------------------------------
public:
void requestUpdate();
BOOL requestUpdateImmediate();
protected:
BOOL isReadyToUpdate() const;
void doUpdate();
void restartUpdateTimer();
private:
BOOL mNeedsUpdate; // Whether we need to locally update our baked textures
U32 mNumLowresUpdates; // Number of times we've locally updated with lowres version of our baked textures
LLFrameTimer mNeedsUpdateTimer; // Tracks time since update was requested and performed.
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -450,14 +450,14 @@ void LLAvatarTexBar::draw()
text_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT);
line_num++;
}
const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureTimeout");
const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureUploadTimeout");
const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel");
LLColor4 header_color(1.f, 1.f, 1.f, 0.9f);
const std::string texture_timeout_str = texture_timeout ? llformat("%d",texture_timeout) : "Disabled";
const std::string override_tex_discard_level_str = override_tex_discard_level ? llformat("%d",override_tex_discard_level) : "Disabled";
std::string header_text = llformat("[ Timeout('AvatarBakedTextureTimeout'):%s ] [ LOD_Override('TextureDiscardLevel'):%s ]", texture_timeout_str.c_str(), override_tex_discard_level_str.c_str());
std::string header_text = llformat("[ Timeout('AvatarBakedTextureUploadTimeout'):%s ] [ LOD_Override('TextureDiscardLevel'):%s ]", texture_timeout_str.c_str(), override_tex_discard_level_str.c_str());
LLFontGL::getFontMonospace()->renderUTF8(header_text, 0, l_offset, v_offset + line_height*line_num,
header_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT);
line_num++;

View File

@ -147,7 +147,7 @@ void LLVisualParamHint::requestHintUpdates( LLVisualParamHint* exception1, LLVis
BOOL LLVisualParamHint::needsRender()
{
return mNeedsUpdate && mDelayFrames-- <= 0 && !gAgentAvatarp->mAppearanceAnimating && mAllowsUpdates;
return mNeedsUpdate && mDelayFrames-- <= 0 && !gAgentAvatarp->getIsAppearanceAnimating() && mAllowsUpdates;
}
void LLVisualParamHint::preRender(BOOL clear_depth)

View File

@ -611,8 +611,9 @@ public:
// Appearance morphing
//--------------------------------------------------------------------
public:
BOOL mAppearanceAnimating;
BOOL getIsAppearanceAnimating() const { return mAppearanceAnimating; }
private:
BOOL mAppearanceAnimating;
LLFrameTimer mAppearanceMorphTimer;
F32 mLastAppearanceBlendTime;
@ -622,7 +623,7 @@ private:
public:
void setClothesColor(LLVOAvatarDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake);
LLColor4 getClothesColor(LLVOAvatarDefines::ETextureIndex te);
static BOOL teToColorParams(LLVOAvatarDefines::ETextureIndex te, U32 *param_name);
static BOOL teToColorParams(LLVOAvatarDefines::ETextureIndex te, U32 *param_name);
//--------------------------------------------------------------------
// Global colors

View File

@ -6343,7 +6343,7 @@ Avatar '[NAME]' left as fully loaded.
name="AvatarRezSelfBakeNotification"
type="notifytip">
( [EXISTENCE] seconds alive )
You uploaded a [RESOLUTION] baked texture for '[BODYREGION]' after [TIME] seconds.
You [ACTION] a [RESOLUTION] baked texture for '[BODYREGION]' after [TIME] seconds.
</notification>
<notification