diff options
Diffstat (limited to 'indra/newview/lltexlayer.cpp')
-rw-r--r-- | indra/newview/lltexlayer.cpp | 256 |
1 files changed, 156 insertions, 100 deletions
diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index b13f9e3898..5d51e32515 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -57,17 +57,52 @@ using namespace LLVOAvatarDefines; +class LLTexLayerInfo +{ + friend class LLTexLayer; + friend class LLTexLayerTemplate; + friend class LLTexLayerInterface; +public: + LLTexLayerInfo(); + ~LLTexLayerInfo(); + + BOOL parseXml(LLXmlTreeNode* node); + BOOL createVisualParams(LLVOAvatar *avatar); + BOOL isUserSettable() { return mLocalTexture != -1; } + S32 getLocalTexture() const { return mLocalTexture; } + BOOL getOnlyAlpha() const { return mUseLocalTextureAlphaOnly; } + std::string getName() const { return mName; } + +private: + std::string mName; + + BOOL mWriteAllChannels; // Don't use masking. Just write RGBA into buffer, + LLTexLayerInterface::ERenderPass mRenderPass; + + std::string mGlobalColor; + LLColor4 mFixedColor; + + S32 mLocalTexture; + std::string mStaticImageFileName; + BOOL mStaticImageIsMask; + BOOL mUseLocalTextureAlphaOnly; // Ignore RGB channels from the input texture. Use alpha as a mask + BOOL mIsVisibilityMask; + + typedef std::vector< std::pair< std::string,BOOL > > morph_name_list_t; + morph_name_list_t mMorphNameList; + param_color_info_list_t mParamColorInfoList; + param_alpha_info_list_t mParamAlphaInfoList; +}; + //----------------------------------------------------------------------------- // LLBakedUploadData() //----------------------------------------------------------------------------- LLBakedUploadData::LLBakedUploadData(const LLVOAvatarSelf* avatar, LLTexLayerSet* layerset, - const LLUUID& id, - BOOL highest_lod) : + const LLUUID& id) : mAvatar(avatar), mTexLayerSet(layerset), mID(id), - mHighestLOD(highest_lod), mStartTime(LLFrameTimer::getTotalTime()) // Record starting time { } @@ -87,7 +122,7 @@ LLTexLayerSetBuffer::LLTexLayerSetBuffer(LLTexLayerSet* const owner, mNeedsUpdate(TRUE), mNeedsUpload(FALSE), mUploadPending(FALSE), // Not used for any logic here, just to sync sending of updates - mDebugNumLowresUploads(0), + mNumLowresUploads(0), mTexLayerSet(owner) { LLTexLayerSetBuffer::sGLByteCount += getSize(); @@ -130,6 +165,7 @@ void LLTexLayerSetBuffer::dumpTotalByteCount() void LLTexLayerSetBuffer::requestUpdate() { + conditionalRestartUploadTimer(); mNeedsUpdate = TRUE; // 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. @@ -138,17 +174,26 @@ void LLTexLayerSetBuffer::requestUpdate() void LLTexLayerSetBuffer::requestUpload() { + conditionalRestartUploadTimer(); + mNeedsUpload = TRUE; + mNumLowresUploads = 0; + mUploadPending = TRUE; +} + +void LLTexLayerSetBuffer::conditionalRestartUploadTimer() +{ // If we requested a new upload but haven't even uploaded // a low res version of our last upload request, then // keep the timer ticking instead of resetting it. - if (mNeedsUpload && (mDebugNumLowresUploads == 0)) + if (mNeedsUpload && (mNumLowresUploads == 0)) + { + mNeedsUploadTimer.unpause(); + } + else { mNeedsUploadTimer.reset(); + mNeedsUploadTimer.start(); } - mNeedsUpload = TRUE; - mDebugNumLowresUploads = 0; - mUploadPending = TRUE; - mNeedsUploadTimer.unpause(); } void LLTexLayerSetBuffer::cancelUpload() @@ -272,11 +317,26 @@ BOOL LLTexLayerSetBuffer::render() return success; } -bool LLTexLayerSetBuffer::isInitialized(void) const +BOOL LLTexLayerSetBuffer::isInitialized(void) const { return mGLTexturep.notNull() && mGLTexturep->isGLTextureCreated(); } +BOOL LLTexLayerSetBuffer::uploadPending() const +{ + return mUploadPending; +} + +BOOL LLTexLayerSetBuffer::uploadNeeded() const +{ + return mNeedsUpload; +} + +BOOL LLTexLayerSetBuffer::uploadInProgress() const +{ + return !mUploadID.isNull(); +} + BOOL LLTexLayerSetBuffer::isReadyToUpload() const { if (!mNeedsUpload) return FALSE; // Don't need to upload if we haven't requested one. @@ -289,8 +349,12 @@ BOOL LLTexLayerSetBuffer::isReadyToUpload() const const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureTimeout"); if (texture_timeout) { + // The timeout period increases exponentially between every lowres upload in order to prevent + // spamming the server with frequent uploads. + const U32 texture_timeout_threshold = texture_timeout*(1 << mNumLowresUploads); + // If we hit our timeout and have textures available at even lower resolution, then upload. - const BOOL is_upload_textures_timeout = mNeedsUploadTimer.getElapsedTimeF32() >= texture_timeout; + const BOOL is_upload_textures_timeout = mNeedsUploadTimer.getElapsedTimeF32() >= texture_timeout_threshold; const BOOL has_lower_lod = mTexLayerSet->isLocalTextureDataAvailable(); if (has_lower_lod && is_upload_textures_timeout) return TRUE; } @@ -314,40 +378,33 @@ BOOL LLTexLayerSetBuffer::updateImmediate() void LLTexLayerSetBuffer::readBackAndUpload() { - // pointers for storing data to upload - U8* baked_color_data = new U8[ mFullWidth * mFullHeight * 4 ]; - - glReadPixels(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data ); - stop_glerror(); - - llinfos << "Baked " << mTexLayerSet->getBodyRegionName() << llendl; + llinfos << "Uploading baked " << mTexLayerSet->getBodyRegionName() << llendl; LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_BAKES); - // We won't need our caches since we're baked now. (Techically, we won't - // really be baked until this image is sent to the server and the Avatar - // Appearance message is received.) + // Don't need caches since we're baked now. (note: we won't *really* be baked + // until this image is sent to the server and the Avatar Appearance message is received.) mTexLayerSet->deleteCaches(); - LLGLSUIDefault gls_ui; + // Get the COLOR information from our texture + U8* baked_color_data = new U8[ mFullWidth * mFullHeight * 4 ]; + glReadPixels(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data ); + stop_glerror(); + // Get the MASK information from our texture + LLGLSUIDefault gls_ui; LLPointer<LLImageRaw> baked_mask_image = new LLImageRaw(mFullWidth, mFullHeight, 1 ); U8* baked_mask_data = baked_mask_image->getData(); - mTexLayerSet->gatherMorphMaskAlpha(baked_mask_data, mFullWidth, mFullHeight); - // writes into baked_color_data - const char* comment_text = NULL; - S32 baked_image_components = 5; // red green blue [bump] clothing + // Create the baked image from our color and mask information + const S32 baked_image_components = 5; // red green blue [bump] clothing LLPointer<LLImageRaw> baked_image = new LLImageRaw( mFullWidth, mFullHeight, baked_image_components ); U8* baked_image_data = baked_image->getData(); - - comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // 5 channels: rgb, heightfield/alpha, mask - S32 i = 0; - for( S32 u = 0; u < mFullWidth; u++ ) + for (S32 u=0; u < mFullWidth; u++) { - for( S32 v = 0; v < mFullHeight; v++ ) + for (S32 v=0; v < mFullHeight; v++) { baked_image_data[5*i + 0] = baked_color_data[4*i + 0]; baked_image_data[5*i + 1] = baked_color_data[4*i + 1]; @@ -360,21 +417,19 @@ void LLTexLayerSetBuffer::readBackAndUpload() LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C; compressedImage->setRate(0.f); - LLTransactionID tid; - LLAssetID asset_id; - tid.generate(); - asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - - BOOL res = false; - if( compressedImage->encode(baked_image, comment_text)) + const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask) + if (compressedImage->encode(baked_image, comment_text)) { - res = LLVFile::writeFile(compressedImage->getData(), compressedImage->getDataSize(), - gVFS, asset_id, LLAssetType::AT_TEXTURE); - if (res) + LLTransactionID tid; + tid.generate(); + const LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + if (LLVFile::writeFile(compressedImage->getData(), compressedImage->getDataSize(), + gVFS, asset_id, LLAssetType::AT_TEXTURE)) { - LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C; + // Read back the file and validate. BOOL valid = FALSE; - S32 file_size; + LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C; + S32 file_size = 0; U8* data = LLVFile::readFile(gVFS, asset_id, LLAssetType::AT_TEXTURE, &file_size); if (data) { @@ -385,32 +440,26 @@ void LLTexLayerSetBuffer::readBackAndUpload() integrity_test->setLastError("Unable to read entire file"); } - if( valid ) + if (valid) { - const BOOL highest_lod = mTexLayerSet->isLocalTextureDataFinal(); - // baked_upload_data is owned by the responder and deleted after the request completes + // Baked_upload_data is owned by the responder and deleted after the request completes. LLBakedUploadData* baked_upload_data = new LLBakedUploadData(gAgentAvatarp, this->mTexLayerSet, - asset_id, - highest_lod); + asset_id); mUploadID = asset_id; - - // upload the image - std::string url = gAgent.getRegion()->getCapability("UploadBakedTexture"); + // Upload the image + const std::string url = gAgent.getRegion()->getCapability("UploadBakedTexture"); if(!url.empty() - && !LLPipeline::sForceOldBakedUpload) // Toggle the debug setting UploadBakedTexOld to change between the new caps method and old method + && !LLPipeline::sForceOldBakedUpload) // toggle debug setting UploadBakedTexOld to change between the new caps method and old method { - llinfos << "Baked texture upload via capability of " << mUploadID << " to " << url << llendl; - LLSD body = LLSD::emptyMap(); + // The responder will call LLTexLayerSetBuffer::onTextureUploadComplete() LLHTTPClient::post(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data)); - // Responder will call LLTexLayerSetBuffer::onTextureUploadComplete() + llinfos << "Baked texture upload via capability of " << mUploadID << " to " << url << llendl; } else { - llinfos << "Baked texture upload via Asset Store." << llendl; - // gAssetStorage->storeAssetData(mTransactionID, LLAssetType::AT_IMAGE_JPEG, &uploadCallback, (void *)this, FALSE); gAssetStorage->storeAssetData(tid, LLAssetType::AT_TEXTURE, LLTexLayerSetBuffer::onTextureUploadComplete, @@ -418,8 +467,26 @@ void LLTexLayerSetBuffer::readBackAndUpload() TRUE, // temp_file TRUE, // is_priority TRUE); // store_local + llinfos << "Baked texture upload via Asset Store." << llendl; + } + + const BOOL highest_lod = mTexLayerSet->isLocalTextureDataFinal(); + if (highest_lod) + { + // Sending the final LOD for the baked texture. All done, pause + // the upload timer so we know how long it took. + mNeedsUpload = FALSE; + mNeedsUploadTimer.pause(); + } + else + { + // Sending a lower level LOD for the baked texture. Restart the upload timer. + mNumLowresUploads++; + mNeedsUploadTimer.unpause(); + mNeedsUploadTimer.reset(); } + // Print out notification that we uploaded this texture. if (gSavedSettings.getBOOL("DebugAvatarRezTime")) { std::string lod_str = highest_lod ? "HighRes" : "LowRes"; @@ -431,36 +498,22 @@ void LLTexLayerSetBuffer::readBackAndUpload() LLNotificationsUtil::add("AvatarRezSelfBakeNotification",args); llinfos << "Uploading [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << llendl; } - - if (highest_lod) - { - // Got the final LOD for the baked texture. - // All done, pause the upload timer so we know how long it took. - mNeedsUpload = FALSE; - mNeedsUploadTimer.pause(); - } - else - { - // Got a lower level LOD for the baked texture. - // Restart the upload timer. - mDebugNumLowresUploads++; - mNeedsUploadTimer.unpause(); - mNeedsUploadTimer.reset(); - } } else { + // The read back and validate operation failed. Remove the uploaded file. mUploadPending = FALSE; - llinfos << "unable to create baked upload file: corrupted" << llendl; LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE, LLVFile::WRITE); file.remove(); + llinfos << "Unable to create baked upload file (reason: corrupted)." << llendl; } } } - if (!res) + else { + // The VFS write file operation failed. mUploadPending = FALSE; - llinfos << "unable to create baked upload file" << llendl; + llinfos << "Unable to create baked upload file (reason: failed to write file)" << llendl; } delete [] baked_color_data; @@ -973,11 +1026,11 @@ void LLTexLayerSet::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_ mAvatar->applyMorphMask(tex_data, width, height, num_components, mBakedTexIndex); } -BOOL LLTexLayerSet::isMorphValid() +BOOL LLTexLayerSet::isMorphValid() const { - for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + for(layer_list_t::const_iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) { - LLTexLayerInterface* layer = *iter; + const LLTexLayerInterface* layer = *iter; if (layer && !layer->isMorphValid()) { return FALSE; @@ -1193,7 +1246,6 @@ BOOL LLTexLayerInfo::createVisualParams(LLVOAvatar *avatar) LLTexLayerInterface::LLTexLayerInterface(LLTexLayerSet* const layer_set): mTexLayerSet( layer_set ), mMorphMasksValid( FALSE ), - mStaticImageInvalid( FALSE ), mInfo(NULL), mHasMorph(FALSE) { @@ -1307,17 +1359,17 @@ void LLTexLayerInterface::invalidateMorphMasks() mMorphMasksValid = FALSE; } -LLViewerVisualParam* LLTexLayerInterface::getVisualParamPtr(S32 index) +LLViewerVisualParam* LLTexLayerInterface::getVisualParamPtr(S32 index) const { LLViewerVisualParam *result = NULL; - for (param_color_list_t::iterator color_iter = mParamColorList.begin(); color_iter != mParamColorList.end() && !result; ++color_iter) + for (param_color_list_t::const_iterator color_iter = mParamColorList.begin(); color_iter != mParamColorList.end() && !result; ++color_iter) { if ((*color_iter)->getID() == index) { result = *color_iter; } } - for (param_alpha_list_t::iterator alpha_iter = mParamAlphaList.begin(); alpha_iter != mParamAlphaList.end() && !result; ++alpha_iter) + for (param_alpha_list_t::const_iterator alpha_iter = mParamAlphaList.begin(); alpha_iter != mParamAlphaList.end() && !result; ++alpha_iter) { if ((*alpha_iter)->getID() == index) { @@ -1571,7 +1623,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) return success; } -U8* LLTexLayer::getAlphaData() +const U8* LLTexLayer::getAlphaData() const { LLCRC alpha_mask_crc; const LLUUID& uuid = getUUID(); @@ -1587,7 +1639,7 @@ U8* LLTexLayer::getAlphaData() U32 cache_index = alpha_mask_crc.getCRC(); - alpha_cache_t::iterator iter2 = mAlphaCache.find(cache_index); + alpha_cache_t::const_iterator iter2 = mAlphaCache.find(cache_index); return (iter2 == mAlphaCache.end()) ? 0 : iter2->second; } @@ -1810,7 +1862,7 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height) { S32 size = width * height; - U8* alphaData = getAlphaData(); + const U8* alphaData = getAlphaData(); if (!alphaData && hasAlphaParams()) { LLColor4 net_color; @@ -1833,7 +1885,7 @@ void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 } } -/*virtual*/ BOOL LLTexLayer::isInvisibleAlphaMask() +/*virtual*/ BOOL LLTexLayer::isInvisibleAlphaMask() const { if (mLocalTextureObject) { @@ -1846,8 +1898,7 @@ void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 return FALSE; } -// private helper function -LLUUID LLTexLayer::getUUID() +LLUUID LLTexLayer::getUUID() const { LLUUID uuid; if( getInfo()->mLocalTexture != -1 ) @@ -1906,7 +1957,7 @@ LLTexLayerTemplate::~LLTexLayerTemplate() return LLTexLayerInterface::setInfo(info, wearable); } -U32 LLTexLayerTemplate::updateWearableCache() +U32 LLTexLayerTemplate::updateWearableCache() const { mWearableCache.clear(); @@ -1931,7 +1982,7 @@ U32 LLTexLayerTemplate::updateWearableCache() } return added; } -LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) +LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const { if (mWearableCache.size() <= i) { @@ -2040,7 +2091,7 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) } } -/*virtual*/ BOOL LLTexLayerTemplate::isInvisibleAlphaMask() +/*virtual*/ BOOL LLTexLayerTemplate::isInvisibleAlphaMask() const { U32 num_wearables = updateWearableCache(); for (U32 i = 0; i < num_wearables; i++) @@ -2064,19 +2115,17 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) //----------------------------------------------------------------------------- LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name) { - for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + for (layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) { LLTexLayerInterface* layer = *iter; - if (layer->getName() == name) { return layer; } } - for( layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++ ) + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++ ) { LLTexLayerInterface* layer = *iter; - if (layer->getName() == name) { return layer; @@ -2121,7 +2170,7 @@ LLTexLayerStaticImageList::~LLTexLayerStaticImageList() deleteCachedImages(); } -void LLTexLayerStaticImageList::dumpByteCount() +void LLTexLayerStaticImageList::dumpByteCount() const { llinfos << "Avatar Static Textures " << "KB GL:" << (mGLBytes / 1024) << @@ -2241,11 +2290,18 @@ const std::string LLTexLayerSetBuffer::dumpTextureInfo() const if (!isAgentAvatarValid()) return ""; const BOOL is_high_res = !mNeedsUpload; - const U32 num_low_res = mDebugNumLowresUploads; + const U32 num_low_res = mNumLowresUploads; const U32 upload_time = (U32)mNeedsUploadTimer.getElapsedTimeF32(); const std::string local_texture_info = gAgentAvatarp->debugDumpLocalTextureDataInfo(mTexLayerSet); - std::string text = llformat("[ HiRes:%d LoRes:%d Timer:%d ] %s", - is_high_res, num_low_res, upload_time, + + std::string status = "CREATING "; + if (!uploadNeeded()) status = "DONE "; + if (uploadInProgress()) status = "UPLOADING"; + + std::string text = llformat("[%s] [HiRes:%d LoRes:%d] [Elapsed:%d] %s", + status.c_str(), + is_high_res, num_low_res, + upload_time, local_texture_info.c_str()); return text; } |