indra/newview/llmeshrepository.cpp

Mon, 29 Jul 2013 12:42:27 -0400

author
Monty Brandenberg <monty@lindenlab.com>
date
Mon, 29 Jul 2013 12:42:27 -0400
changeset 40698
8daa5f3fcf2e
parent 40697
1909fb80b76f
child 40701
708f569ab46b
permissions
-rwxr-xr-x

SH-4368 Adjust upload timeout parameters for slow networks.
Generally sorted the mesh timeout parameters for maximum
transport time (staying with default 30 for connect). 60S
for normal meshes, 600S for large. Also documented default
option values in httpoptions.h. Useful to have these. In
the future, the timeouts might go into standard llsd options
where they can be tracked a bit more.

     2 /** 
     3  * @file llmeshrepository.cpp
     4  * @brief Mesh repository implementation.
     5  *
     6  * $LicenseInfo:firstyear=2005&license=viewerlgpl$
     7  * Second Life Viewer Source Code
     8  * Copyright (C) 2010-2013, Linden Research, Inc.
     9  * 
    10  * This library is free software; you can redistribute it and/or
    11  * modify it under the terms of the GNU Lesser General Public
    12  * License as published by the Free Software Foundation;
    13  * version 2.1 of the License only.
    14  * 
    15  * This library is distributed in the hope that it will be useful,
    16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    18  * Lesser General Public License for more details.
    19  * 
    20  * You should have received a copy of the GNU Lesser General Public
    21  * License along with this library; if not, write to the Free Software
    22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
    23  * 
    24  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
    25  * $/LicenseInfo$
    26  */
    28 #include "llviewerprecompiledheaders.h"
    30 #include "apr_pools.h"
    31 #include "apr_dso.h"
    32 #include "llhttpstatuscodes.h"
    33 #include "llmeshrepository.h"
    35 #include "llagent.h"
    36 #include "llappviewer.h"
    37 #include "llbufferstream.h"
    38 #include "llcallbacklist.h"
    39 #include "llcurl.h"
    40 #include "lldatapacker.h"
    41 #include "lldeadmantimer.h"
    42 #include "llfloatermodelpreview.h"
    43 #include "llfloaterperms.h"
    44 #include "lleconomy.h"
    45 #include "llimagej2c.h"
    46 #include "llhost.h"
    47 #include "llnotificationsutil.h"
    48 #include "llsd.h"
    49 #include "llsdutil_math.h"
    50 #include "llsdserialize.h"
    51 #include "llthread.h"
    52 #include "llvfile.h"
    53 #include "llviewercontrol.h"
    54 #include "llviewerinventory.h"
    55 #include "llviewermenufile.h"
    56 #include "llviewermessage.h"
    57 #include "llviewerobjectlist.h"
    58 #include "llviewerregion.h"
    59 #include "llviewertexturelist.h"
    60 #include "llvolume.h"
    61 #include "llvolumemgr.h"
    62 #include "llvovolume.h"
    63 #include "llworld.h"
    64 #include "material_codes.h"
    65 #include "pipeline.h"
    66 #include "llinventorymodel.h"
    67 #include "llfoldertype.h"
    68 #include "llviewerparcelmgr.h"
    69 #include "lluploadfloaterobservers.h"
    70 #include "bufferarray.h"
    71 #include "bufferstream.h"
    73 #include "boost/lexical_cast.hpp"
    75 #ifndef LL_WINDOWS
    76 #include "netdb.h"
    77 #endif
    79 #include <queue>
    82 // [ Disclaimer:  this documentation isn't by one of the original authors
    83 //   but by someone coming through later and extracting intent and function.
    84 //   Some of this will be wrong so use judgement. ]
    85 //
    86 // Purpose
    87 //
    88 //   The purpose of this module is to provide access between the viewer
    89 //   and the asset system as regards to mesh objects.
    90 //
    91 //   * High-throughput download of mesh assets from servers while
    92 //     following best industry practices for network profile.
    93 //   * Reliable expensing and upload of new mesh assets.
    94 //   * Recovery and retry from errors when appropriate.
    95 //   * Decomposition of mesh assets for preview and uploads.
    96 //   * And most important:  all of the above without exposing the
    97 //     main thread to stalls due to deep processing or thread
    98 //     locking actions.  In particular, the following operations
    99 //     on LLMeshRepository are very averse to any stalls:
   100 //     * loadMesh
   101 //     * getMeshHeader (For structural details, see:
   102 //       http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format)
   103 //     * notifyLoadedMeshes
   104 //
   105 // Threads
   106 //
   107 //   main     Main rendering thread, very sensitive to locking and other stalls
   108 //   repo     Overseeing worker thread associated with the LLMeshRepoThread class
   109 //   decom    Worker thread for mesh decomposition requests
   110 //   core     HTTP worker thread:  does the work but doesn't intrude here
   111 //   uploadN  0-N temporary mesh upload threads
   112 //
   113 // Mutexes
   114 //
   115 //   LLMeshRepository::mMeshMutex
   116 //   LLMeshRepoThread::mMutex
   117 //   LLMeshRepoThread::mHeaderMutex
   118 //   LLMeshRepoThread::mSignal (LLCondition)
   119 //   LLPhysicsDecomp::mSignal (LLCondition)
   120 //   LLPhysicsDecomp::mMutex
   121 //   LLMeshUploadThread::mMutex
   122 //
   123 // Mutex Order Rules
   124 //
   125 //   1.  LLMeshRepoThread::mMutex before LLMeshRepoThread::mHeaderMutex
   126 //   2.  LLMeshRepository::mMeshMutex before LLMeshRepoThread::mMutex
   127 //   (There are more rules, haven't been extracted.)
   128 //
   129 // Data Member Access/Locking
   130 //
   131 //   Description of how shared access to static and instance data
   132 //   members is performed.  Each member is followed by the name of
   133 //   the mutex, if any, covering the data and then a list of data
   134 //   access models each of which is a triplet of the following form:
   135 //
   136 //     {ro, wo, rw}.{main, repo, any}.{mutex, none}
   137 //     Type of access:  read-only, write-only, read-write.
   138 //     Accessing thread or 'any'
   139 //     Relevant mutex held during access (several may be held) or 'none'
   140 //
   141 //   A careful eye will notice some unsafe operations.  Many of these
   142 //   have an alibi of some form.  Several types of alibi are identified
   143 //   and listed here:
   144 //
   145 //     [0]  No alibi.  Probably unsafe.
   146 //     [1]  Single-writer, self-consistent readers.  Old data must
   147 //          be tolerated by any reader but data will come true eventually.
   148 //     [2]  Like [1] but provides a hint about thread state.  These
   149 //          may be unsafe.
   150 //     [3]  empty() check outside of lock.  Can me made safish when
   151 //          done in double-check lock style.  But this depends on
   152 //          std:: implementation and memory model.
   153 //     [4]  Appears to be covered by a mutex but doesn't need one.
   154 //     [5]  Read of a double-checked lock.
   155 //
   156 //   So, in addition to documentation, take this as a to-do/review
   157 //   list and see if you can improve things.  For porters to non-x86
   158 //   architectures, including amd64, the weaker memory models will
   159 //   make these platforms probabilistically more susceptible to hitting
   160 //   race conditions.  True here and in other multi-thread code such
   161 //   as texture fetching.
   162 //
   163 //   LLMeshRepository:
   164 //
   165 //     sBytesReceived
   166 //     sHTTPRequestCount
   167 //     sHTTPRetryCount
   168 //     sLODPending
   169 //     sLODProcessing
   170 //     sCacheBytesRead
   171 //     sCacheBytesWritten
   172 //     mLoadingMeshes                  none            rw.main.none, rw.main.mMeshMutex [4]
   173 //     mSkinMap                        none            rw.main.none
   174 //     mDecompositionMap               none            rw.main.none
   175 //     mPendingRequests                mMeshMutex [4]  rw.main.mMeshMutex
   176 //     mLoadingSkins                   mMeshMutex [4]  rw.main.mMeshMutex
   177 //     mPendingSkinRequests            mMeshMutex [4]  rw.main.mMeshMutex
   178 //     mLoadingDecompositions          mMeshMutex [4]  rw.main.mMeshMutex
   179 //     mPendingDecompositionRequests   mMeshMutex [4]  rw.main.mMeshMutex
   180 //     mLoadingPhysicsShapes           mMeshMutex [4]  rw.main.mMeshMutex
   181 //     mPendingPhysicsShapeRequests    mMeshMutex [4]  rw.main.mMeshMutex
   182 //     mUploads                        none            rw.main.none (upload thread accessing objects)
   183 //     mUploadWaitList                 none            rw.main.none (upload thread accessing objects)
   184 //     mInventoryQ                     mMeshMutex [4]  rw.main.mMeshMutex, ro.main.none [5]
   185 //     mUploadErrorQ                   mMeshMutex      rw.main.mMeshMutex, rw.any.mMeshMutex
   186 //     mGetMeshCapability              none            rw.main.none [0], ro.any.none
   187 //     mGetMesh2Capability             none            rw.main.none [0], ro.any.none
   188 //
   189 //   LLMeshRepoThread:
   190 //
   191 //     sActiveHeaderRequests    mMutex        rw.any.mMutex, ro.repo.none [1]
   192 //     sActiveLODRequests       mMutex        rw.any.mMutex, ro.repo.none [1]
   193 //     sMaxConcurrentRequests   mMutex        wo.main.none, ro.repo.none, ro.main.mMutex
   194 //     mWaiting                 mMutex        rw.repo.none, ro.main.none [2] (race - hint)
   195 //     mMeshHeader              mHeaderMutex  rw.repo.mHeaderMutex, ro.main.mHeaderMutex, ro.main.none [0]
   196 //     mMeshHeaderSize          mHeaderMutex  rw.repo.mHeaderMutex
   197 //     mSkinRequests            none          rw.repo.none, rw.main.none [0]
   198 //     mSkinInfoQ               none          rw.repo.none, rw.main.none [0]
   199 //     mDecompositionRequests   none          rw.repo.none, rw.main.none [0]
   200 //     mPhysicsShapeRequests    none          rw.repo.none, rw.main.none [0]
   201 //     mDecompositionQ          none          rw.repo.none, rw.main.none [0]
   202 //     mHeaderReqQ              mMutex        ro.repo.none [3], rw.repo.mMutex, rw.any.mMutex
   203 //     mLODReqQ                 mMutex        ro.repo.none [3], rw.repo.mMutex, rw.any.mMutex
   204 //     mUnavailableQ            mMutex        rw.repo.none [0], ro.main.none [3], rw.main.mMutex
   205 //     mLoadedQ                 mMutex        rw.repo.mMutex, ro.main.none [3], rw.main.mMutex
   206 //     mPendingLOD              mMutex        rw.repo.mMutex, rw.any.mMutex
   207 //     mHttp*                   none          rw.repo.none
   208 //
   209 //   LLPhysicsDecomp:
   210 //    
   211 //     mRequestQ
   212 //     mCurRequest
   213 //     mCompletedQ
   214 //
   215 //
   216 // QA/Development Testing
   217 //
   218 //   Debug variable 'MeshUploadFakeErrors' takes a mask of bits that will
   219 //   simulate an error on fee query or upload.  Defined bits are:
   220 //
   221 //   0x01            Simulate application error on fee check reading
   222 //                   response body from file "fake_upload_error.xml"
   223 //   0x02            Same as 0x01 but for actual upload attempt.
   224 //   0x04            Simulate a transport problem on fee check with a
   225 //                   locally-generated 500 status.
   226 //   0x08            As with 0x04 but for the upload operation.
   227 //
   229 LLMeshRepository gMeshRepo;
   231 const S32 MESH_HEADER_SIZE = 4096;                      // Important:  assumption is that headers fit in this space
   232 const U32 MAX_MESH_REQUESTS_PER_SECOND = 100;
   233 const S32 REQUEST_HIGH_WATER_MIN = 32;
   234 const S32 REQUEST_HIGH_WATER_MAX = 80;
   235 const S32 REQUEST_LOW_WATER_MIN = 16;
   236 const S32 REQUEST_LOW_WATER_MAX = 40;
   237 const U32 LARGE_MESH_FETCH_THRESHOLD = 1U << 21;		// Size at which requests goes to narrow/slow queue
   238 const long SMALL_MESH_XFER_TIMEOUT = 60L;				// Seconds to complete xfer, small mesh downloads
   239 const long LARGE_MESH_XFER_TIMEOUT = 600L;				// Seconds to complete xfer, large downloads
   241 // Maximum mesh version to support.  Three least significant digits are reserved for the minor version, 
   242 // with major version changes indicating a format change that is not backwards compatible and should not
   243 // be parsed by viewers that don't specifically support that version. For example, if the integer "1" is 
   244 // present, the version is 0.001. A viewer that can parse version 0.001 can also parse versions up to 0.999, 
   245 // but not 1.0 (integer 1000).
   246 // See wiki at https://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format
   247 const S32 MAX_MESH_VERSION = 999;
   249 U32 LLMeshRepository::sBytesReceived = 0;
   250 U32 LLMeshRepository::sHTTPRequestCount = 0;
   251 U32 LLMeshRepository::sHTTPRetryCount = 0;
   252 U32 LLMeshRepository::sLODProcessing = 0;
   253 U32 LLMeshRepository::sLODPending = 0;
   255 U32 LLMeshRepository::sCacheBytesRead = 0;
   256 U32 LLMeshRepository::sCacheBytesWritten = 0;
   257 LLDeadmanTimer LLMeshRepository::sQuiescentTimer(15.0, true);	// true -> gather cpu metrics
   260 static S32 dump_num = 0;
   261 std::string make_dump_name(std::string prefix, S32 num)
   262 {
   263 	return prefix + boost::lexical_cast<std::string>(num) + std::string(".xml");
   265 }
   266 void dump_llsd_to_file(const LLSD& content, std::string filename);
   267 LLSD llsd_from_file(std::string filename);
   269 const std::string header_lod[] = 
   270 {
   271 	"lowest_lod",
   272 	"low_lod",
   273 	"medium_lod",
   274 	"high_lod"
   275 };
   276 const char * const LOG_MESH = "Mesh";
   278 // Static data and functions to measure mesh load
   279 // time metrics for a new region scene.
   280 static unsigned int metrics_teleport_start_count(0);
   281 boost::signals2::connection metrics_teleport_started_signal;
   282 static void teleport_started();
   283 static bool is_retryable(LLCore::HttpStatus status);
   285 //get the number of bytes resident in memory for given volume
   286 U32 get_volume_memory_size(const LLVolume* volume)
   287 {
   288 	U32 indices = 0;
   289 	U32 vertices = 0;
   291 	for (U32 i = 0; i < volume->getNumVolumeFaces(); ++i)
   292 	{
   293 		const LLVolumeFace& face = volume->getVolumeFace(i);
   294 		indices += face.mNumIndices;
   295 		vertices += face.mNumVertices;
   296 	}
   299 	return indices*2+vertices*11+sizeof(LLVolume)+sizeof(LLVolumeFace)*volume->getNumVolumeFaces();
   300 }
   302 void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res, F32 scale = 1.f)
   303 {
   304 	res.mPositions.clear();
   305 	res.mNormals.clear();
   307 	const F32* v = mesh.mVertexBase;
   309 	if (mesh.mIndexType == LLCDMeshData::INT_16)
   310 	{
   311 		U16* idx = (U16*) mesh.mIndexBase;
   312 		for (S32 j = 0; j < mesh.mNumTriangles; ++j)
   313 		{ 
   314 			F32* mp0 = (F32*) ((U8*)v+idx[0]*mesh.mVertexStrideBytes);
   315 			F32* mp1 = (F32*) ((U8*)v+idx[1]*mesh.mVertexStrideBytes);
   316 			F32* mp2 = (F32*) ((U8*)v+idx[2]*mesh.mVertexStrideBytes);
   318 			idx = (U16*) (((U8*)idx)+mesh.mIndexStrideBytes);
   320 			LLVector3 v0(mp0);
   321 			LLVector3 v1(mp1);
   322 			LLVector3 v2(mp2);
   324 			LLVector3 n = (v1-v0)%(v2-v0);
   325 			n.normalize();
   327 			res.mPositions.push_back(v0*scale);
   328 			res.mPositions.push_back(v1*scale);
   329 			res.mPositions.push_back(v2*scale);
   331 			res.mNormals.push_back(n);
   332 			res.mNormals.push_back(n);
   333 			res.mNormals.push_back(n);			
   334 		}
   335 	}
   336 	else
   337 	{
   338 		U32* idx = (U32*) mesh.mIndexBase;
   339 		for (S32 j = 0; j < mesh.mNumTriangles; ++j)
   340 		{ 
   341 			F32* mp0 = (F32*) ((U8*)v+idx[0]*mesh.mVertexStrideBytes);
   342 			F32* mp1 = (F32*) ((U8*)v+idx[1]*mesh.mVertexStrideBytes);
   343 			F32* mp2 = (F32*) ((U8*)v+idx[2]*mesh.mVertexStrideBytes);
   345 			idx = (U32*) (((U8*)idx)+mesh.mIndexStrideBytes);
   347 			LLVector3 v0(mp0);
   348 			LLVector3 v1(mp1);
   349 			LLVector3 v2(mp2);
   351 			LLVector3 n = (v1-v0)%(v2-v0);
   352 			n.normalize();
   354 			res.mPositions.push_back(v0*scale);
   355 			res.mPositions.push_back(v1*scale);
   356 			res.mPositions.push_back(v2*scale);
   358 			res.mNormals.push_back(n);
   359 			res.mNormals.push_back(n);
   360 			res.mNormals.push_back(n);			
   361 		}
   362 	}
   363 }
   365 volatile S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
   366 volatile S32 LLMeshRepoThread::sActiveLODRequests = 0;
   367 U32	LLMeshRepoThread::sMaxConcurrentRequests = 1;
   368 S32 LLMeshRepoThread::sRequestLowWater = REQUEST_LOW_WATER_MIN;
   369 S32 LLMeshRepoThread::sRequestHighWater = REQUEST_HIGH_WATER_MIN;
   371 // Base handler class for all mesh users of llcorehttp.
   372 // This is roughly equivalent to a Responder class in
   373 // traditional LL code.  The base is going to perform
   374 // common response/data handling in the inherited
   375 // onCompleted() method.  Derived classes, one for each
   376 // type of HTTP action, define processData() and
   377 // processFailure() methods to customize handling and
   378 // error messages.
   379 //
   380 // LLCore::HttpHandler
   381 //   LLMeshHandlerBase
   382 //     LLMeshHeaderHandler
   383 //     LLMeshLODHandler
   384 //     LLMeshSkinInfoHandler
   385 //     LLMeshDecompositionHandler
   386 //     LLMeshPhysicsShapeHandler
   388 class LLMeshHandlerBase : public LLCore::HttpHandler
   389 {
   390 public:
   391 	LLMeshHandlerBase()
   392 		: LLCore::HttpHandler(),
   393 		  mMeshParams(),
   394 		  mProcessed(false),
   395 		  mHttpHandle(LLCORE_HTTP_HANDLE_INVALID)
   396 		{}
   398 	virtual ~LLMeshHandlerBase()
   399 		{}
   401 protected:
   402 	LLMeshHandlerBase(const LLMeshHandlerBase &);				// Not defined
   403 	void operator=(const LLMeshHandlerBase &);					// Not defined
   405 public:
   406 	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
   407 	virtual void processData(LLCore::BufferArray * body, U8 * data, S32 data_size) = 0;
   408 	virtual void processFailure(LLCore::HttpStatus status) = 0;
   410 public:
   411 	LLVolumeParams		mMeshParams;
   412 	bool				mProcessed;
   413 	LLCore::HttpHandle	mHttpHandle;
   414 };
   417 // Subclass for header fetches.
   418 //
   419 // Thread:  repo
   420 class LLMeshHeaderHandler : public LLMeshHandlerBase
   421 {
   422 public:
   423 	LLMeshHeaderHandler(const LLVolumeParams & mesh_params)
   424 		: LLMeshHandlerBase()
   425 	{
   426 		mMeshParams = mesh_params;
   427 		LLMeshRepoThread::incActiveHeaderRequests();
   428 	}
   429 	virtual ~LLMeshHeaderHandler();
   431 protected:
   432 	LLMeshHeaderHandler(const LLMeshHeaderHandler &);			// Not defined
   433 	void operator=(const LLMeshHeaderHandler &);				// Not defined
   435 public:
   436 	virtual void processData(LLCore::BufferArray * body, U8 * data, S32 data_size);
   437 	virtual void processFailure(LLCore::HttpStatus status);
   438 };
   441 // Subclass for LOD fetches.
   442 //
   443 // Thread:  repo
   444 class LLMeshLODHandler : public LLMeshHandlerBase
   445 {
   446 public:
   447 	LLMeshLODHandler(const LLVolumeParams & mesh_params, S32 lod, U32 offset, U32 requested_bytes)
   448 		: LLMeshHandlerBase(),
   449 		  mLOD(lod),
   450 		  mRequestedBytes(requested_bytes),
   451 		  mOffset(offset)
   452 	{
   453 		mMeshParams = mesh_params;
   454 		LLMeshRepoThread::incActiveLODRequests();
   455 	}
   456 	virtual ~LLMeshLODHandler();
   458 protected:
   459 	LLMeshLODHandler(const LLMeshLODHandler &);					// Not defined
   460 	void operator=(const LLMeshLODHandler &);					// Not defined
   462 public:
   463 	virtual void processData(LLCore::BufferArray * body, U8 * data, S32 data_size);
   464 	virtual void processFailure(LLCore::HttpStatus status);
   466 public:
   467 	S32 mLOD;
   468 	U32 mRequestedBytes;
   469 	U32 mOffset;
   470 };
   473 // Subclass for skin info fetches.
   474 //
   475 // Thread:  repo
   476 class LLMeshSkinInfoHandler : public LLMeshHandlerBase
   477 {
   478 public:
   479 	LLMeshSkinInfoHandler(const LLUUID& id, U32 offset, U32 size)
   480 		: LLMeshHandlerBase(),
   481 		  mMeshID(id),
   482 		  mRequestedBytes(size),
   483 		  mOffset(offset)
   484 	{}
   485 	virtual ~LLMeshSkinInfoHandler();
   487 protected:
   488 	LLMeshSkinInfoHandler(const LLMeshSkinInfoHandler &);		// Not defined
   489 	void operator=(const LLMeshSkinInfoHandler &);				// Not defined
   491 public:
   492 	virtual void processData(LLCore::BufferArray * body, U8 * data, S32 data_size);
   493 	virtual void processFailure(LLCore::HttpStatus status);
   495 public:
   496 	LLUUID mMeshID;
   497 	U32 mRequestedBytes;
   498 	U32 mOffset;
   499 };
   502 // Subclass for decomposition fetches.
   503 //
   504 // Thread:  repo
   505 class LLMeshDecompositionHandler : public LLMeshHandlerBase
   506 {
   507 public:
   508 	LLMeshDecompositionHandler(const LLUUID& id, U32 offset, U32 size)
   509 		: LLMeshHandlerBase(),
   510 		  mMeshID(id),
   511 		  mRequestedBytes(size),
   512 		  mOffset(offset)
   513 	{}
   514 	virtual ~LLMeshDecompositionHandler();
   516 protected:
   517 	LLMeshDecompositionHandler(const LLMeshDecompositionHandler &);		// Not defined
   518 	void operator=(const LLMeshDecompositionHandler &);					// Not defined
   520 public:
   521 	virtual void processData(LLCore::BufferArray * body, U8 * data, S32 data_size);
   522 	virtual void processFailure(LLCore::HttpStatus status);
   524 public:
   525 	LLUUID mMeshID;
   526 	U32 mRequestedBytes;
   527 	U32 mOffset;
   528 };
   531 // Subclass for physics shape fetches.
   532 //
   533 // Thread:  repo
   534 class LLMeshPhysicsShapeHandler : public LLMeshHandlerBase
   535 {
   536 public:
   537 	LLMeshPhysicsShapeHandler(const LLUUID& id, U32 offset, U32 size)
   538 		: LLMeshHandlerBase(),
   539 		  mMeshID(id),
   540 		  mRequestedBytes(size),
   541 		  mOffset(offset)
   542 	{}
   543 	virtual ~LLMeshPhysicsShapeHandler();
   545 protected:
   546 	LLMeshPhysicsShapeHandler(const LLMeshPhysicsShapeHandler &);	// Not defined
   547 	void operator=(const LLMeshPhysicsShapeHandler &);				// Not defined
   549 public:
   550 	virtual void processData(LLCore::BufferArray * body, U8 * data, S32 data_size);
   551 	virtual void processFailure(LLCore::HttpStatus status);
   553 public:
   554 	LLUUID		mMeshID;
   555 	U32			mRequestedBytes;
   556 	U32			mOffset;
   557 };
   560 void log_upload_error(LLCore::HttpStatus status, const LLSD& content,
   561 					  const char * const stage, const std::string & model_name)
   562 {
   563 	// Add notification popup.
   564 	LLSD args;
   565 	std::string message = content["error"]["message"].asString();
   566 	std::string identifier = content["error"]["identifier"].asString();
   567 	args["MESSAGE"] = message;
   568 	args["IDENTIFIER"] = identifier;
   569 	args["LABEL"] = model_name;
   570 	gMeshRepo.uploadError(args);
   572 	// Log details.
   573 	LL_WARNS(LOG_MESH) << "Error in stage:  " << stage
   574 					   << ", Reason:  " << status.toString()
   575 					   << " (" << status.toHex() << ")" << LL_ENDL;
   576 	if (content.has("error"))
   577 	{
   578 		const LLSD& err = content["error"];
   579 		LL_WARNS(LOG_MESH) << "error: " << err << LL_ENDL;
   580 		LL_WARNS(LOG_MESH) << "  mesh upload failed, stage '" << stage
   581 						   << "', error '" << err["error"].asString()
   582 						   << "', message '" << err["message"].asString()
   583 						   << "', id '" << err["identifier"].asString()
   584 						   << "'" << LL_ENDL;
   585 		if (err.has("errors"))
   586 		{
   587 			S32 error_num = 0;
   588 			const LLSD& err_list = err["errors"];
   589 			for (LLSD::array_const_iterator it = err_list.beginArray();
   590 				 it != err_list.endArray();
   591 				 ++it)
   592 			{
   593 				const LLSD& err_entry = *it;
   594 				LL_WARNS(LOG_MESH) << "  error[" << error_num << "]:" << LL_ENDL;
   595 				for (LLSD::map_const_iterator map_it = err_entry.beginMap();
   596 					 map_it != err_entry.endMap();
   597 					 ++map_it)
   598 				{
   599 					LL_WARNS(LOG_MESH) << "    " << map_it->first << ":  "
   600 									   << map_it->second << LL_ENDL;
   601 				}
   602 				error_num++;
   603 			}
   604 		}
   605 	}
   606 	else
   607 	{
   608 		LL_WARNS(LOG_MESH) << "Bad response to mesh request, no additional error information available." << LL_ENDL;
   609 	}
   610 }
   613 LLMeshRepoThread::LLMeshRepoThread()
   614 : LLThread("mesh repo"),
   615   mWaiting(false),
   616   mHttpRetries(0U),
   617   mHttpRequest(NULL),
   618   mHttpOptions(NULL),
   619   mHttpLargeOptions(NULL),
   620   mHttpHeaders(NULL),
   621   mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
   622   mHttpLegacyPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
   623   mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
   624   mHttpPriority(0),
   625   mHttpGetCount(0U),
   626   mHttpLargeGetCount(0U)
   627 { 
   628 	mMutex = new LLMutex(NULL);
   629 	mHeaderMutex = new LLMutex(NULL);
   630 	mSignal = new LLCondition(NULL);
   631 	mHttpRequest = new LLCore::HttpRequest;
   632 	mHttpOptions = new LLCore::HttpOptions;
   633 	mHttpOptions->setTransferTimeout(SMALL_MESH_XFER_TIMEOUT);
   634 	mHttpLargeOptions = new LLCore::HttpOptions;
   635 	mHttpLargeOptions->setTransferTimeout(LARGE_MESH_XFER_TIMEOUT);
   636 	mHttpHeaders = new LLCore::HttpHeaders;
   637 	mHttpHeaders->append("Accept", "application/vnd.ll.mesh");
   638 	mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_MESH2);
   639 	mHttpLegacyPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_MESH1);
   640 	mHttpLargePolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_LARGE_MESH);
   641 }
   644 LLMeshRepoThread::~LLMeshRepoThread()
   645 {
   646 	LL_INFOS(LOG_MESH) << "Small GETs issued:  " << mHttpGetCount
   647 					   << ", Large GETs issued:  " << mHttpLargeGetCount
   648 					   << LL_ENDL;
   650 	for (http_request_set::iterator iter(mHttpRequestSet.begin());
   651 		 iter != mHttpRequestSet.end();
   652 		 ++iter)
   653 	{
   654 		delete *iter;
   655 	}
   656 	mHttpRequestSet.clear();
   657 	if (mHttpHeaders)
   658 	{
   659 		mHttpHeaders->release();
   660 		mHttpHeaders = NULL;
   661 	}
   662 	if (mHttpOptions)
   663 	{
   664 		mHttpOptions->release();
   665 		mHttpOptions = NULL;
   666 	}
   667 	if (mHttpLargeOptions)
   668 	{
   669 		mHttpLargeOptions->release();
   670 		mHttpLargeOptions = NULL;
   671 	}
   672 	delete mHttpRequest;
   673 	mHttpRequest = NULL;
   674 	delete mMutex;
   675 	mMutex = NULL;
   676 	delete mHeaderMutex;
   677 	mHeaderMutex = NULL;
   678 	delete mSignal;
   679 	mSignal = NULL;
   680 }
   682 void LLMeshRepoThread::run()
   683 {
   684 	LLCDResult res = LLConvexDecomposition::initThread();
   685 	if (res != LLCD_OK)
   686 	{
   687 		LL_WARNS(LOG_MESH) << "Convex decomposition unable to be loaded.  Expect severe problems." << LL_ENDL;
   688 	}
   690 	while (!LLApp::isQuitting())
   691 	{
   692 		if (! mHttpRequestSet.empty())
   693 		{
   694 			// Dispatch all HttpHandler notifications
   695 			mHttpRequest->update(0L);
   696 		}
   698 		mWaiting = true;
   699 		mSignal->wait();
   700 		mWaiting = false;
   702 		if (! LLApp::isQuitting())
   703 		{
   704 			static U32 count = 0;
   705 			static F32 last_hundred = gFrameTimeSeconds;
   707 			if (gFrameTimeSeconds - last_hundred > 1.f)
   708 			{ //a second has gone by, clear count
   709 				last_hundred = gFrameTimeSeconds;
   710 				count = 0;
   711 			}
   712 			else
   713 			{
   714 				count += mHttpRetries;
   715 			}
   716 			mHttpRetries = 0U;
   718 			// NOTE: throttling intentionally favors LOD requests over header requests
   720 			while (!mLODReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && mHttpRequestSet.size() < sRequestHighWater)
   721 			{
   722 				if (! mMutex)
   723 				{
   724 					break;
   725 				}
   726 				mMutex->lock();
   727 				LODRequest req = mLODReqQ.front();
   728 				mLODReqQ.pop();
   729 				LLMeshRepository::sLODProcessing--;
   730 				mMutex->unlock();
   731 				if (!fetchMeshLOD(req.mMeshParams, req.mLOD, count))//failed, resubmit
   732 				{
   733 					mMutex->lock();
   734 					mLODReqQ.push(req) ; 
   735 					++LLMeshRepository::sLODProcessing;
   736 					mMutex->unlock();
   737 				}
   738 			}
   740 			while (!mHeaderReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && mHttpRequestSet.size() < sRequestHighWater)
   741 			{
   742 				if (! mMutex)
   743 				{
   744 					break;
   745 				}
   746 				mMutex->lock();
   747 				HeaderRequest req = mHeaderReqQ.front();
   748 				mHeaderReqQ.pop();
   749 				mMutex->unlock();
   750 				if (!fetchMeshHeader(req.mMeshParams, count))//failed, resubmit
   751 				{
   752 					mMutex->lock();
   753 					mHeaderReqQ.push(req) ;
   754 					mMutex->unlock();
   755 				}
   756 			}
   758 			// For the final three request lists, if we scan any part of one
   759 			// list, we scan the entire thing.  This gets us through any requests
   760 			// which can be resolved in the cache.  It also keeps the request
   761 			// set somewhat fresher otherwise items at the end of the set
   762 			// order will lose.  Keep to the throttle enforcement and pay
   763 			// attention to the highwater level (enforced in each fetchXXX()
   764 			// method).
   765 			if (! mSkinRequests.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && mHttpRequestSet.size() < sRequestHighWater)
   766 			{
   767 				// *FIXME:  this really does need a lock as do the following ones
   768 				std::set<LLUUID> incomplete;
   769 				for (std::set<LLUUID>::iterator iter = mSkinRequests.begin(); iter != mSkinRequests.end(); ++iter)
   770 				{
   771 					LLUUID mesh_id = *iter;
   772 					if (!fetchMeshSkinInfo(mesh_id, count))
   773 					{
   774 						incomplete.insert(mesh_id);
   775 					}
   776 				}
   777 				mSkinRequests.swap(incomplete);
   778 			}
   780 			if (! mDecompositionRequests.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && mHttpRequestSet.size() < sRequestHighWater)
   781 			{
   782 				std::set<LLUUID> incomplete;
   783 				for (std::set<LLUUID>::iterator iter = mDecompositionRequests.begin(); iter != mDecompositionRequests.end(); ++iter)
   784 				{
   785 					LLUUID mesh_id = *iter;
   786 					if (!fetchMeshDecomposition(mesh_id, count))
   787 					{
   788 						incomplete.insert(mesh_id);
   789 					}
   790 				}
   791 				mDecompositionRequests.swap(incomplete);
   792 			}
   794 			if (! mPhysicsShapeRequests.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && mHttpRequestSet.size() < sRequestHighWater)
   795 			{
   796 				std::set<LLUUID> incomplete;
   797 				for (std::set<LLUUID>::iterator iter = mPhysicsShapeRequests.begin(); iter != mPhysicsShapeRequests.end(); ++iter)
   798 				{
   799 					LLUUID mesh_id = *iter;
   800 					if (!fetchMeshPhysicsShape(mesh_id, count))
   801 					{
   802 						incomplete.insert(mesh_id);
   803 					}
   804 				}
   805 				mPhysicsShapeRequests.swap(incomplete);
   806 			}
   808 			// For dev purposes, a dynamic change could make this false
   809 			// and that shouldn't assert.
   810 			// llassert_always(mHttpRequestSet.size() <= sRequestHighWater);
   811 		}
   812 	}
   814 	if (mSignal->isLocked())
   815 	{ //make sure to let go of the mutex associated with the given signal before shutting down
   816 		mSignal->unlock();
   817 	}
   819 	res = LLConvexDecomposition::quitThread();
   820 	if (res != LLCD_OK)
   821 	{
   822 		LL_WARNS(LOG_MESH) << "Convex decomposition unable to be quit." << LL_ENDL;
   823 	}
   824 }
   826 void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id)
   827 { //protected by mSignal, no locking needed here
   828 	mSkinRequests.insert(mesh_id);
   829 }
   831 void LLMeshRepoThread::loadMeshDecomposition(const LLUUID& mesh_id)
   832 { //protected by mSignal, no locking needed here
   833 	mDecompositionRequests.insert(mesh_id);
   834 }
   836 void LLMeshRepoThread::loadMeshPhysicsShape(const LLUUID& mesh_id)
   837 { //protected by mSignal, no locking needed here
   838 	mPhysicsShapeRequests.insert(mesh_id);
   839 }
   841 void LLMeshRepoThread::lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
   842 {
   843 	if (!LLAppViewer::isQuitting())
   844 	{
   845 		loadMeshLOD(mesh_params, lod);
   846 	}
   847 }
   850 void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
   851 { //could be called from any thread
   852 	LLMutexLock lock(mMutex);
   853 	mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID());
   854 	if (iter != mMeshHeader.end())
   855 	{ //if we have the header, request LOD byte range
   856 		LODRequest req(mesh_params, lod);
   857 		{
   858 			mLODReqQ.push(req);
   859 			LLMeshRepository::sLODProcessing++;
   860 		}
   861 	}
   862 	else
   863 	{ 
   864 		HeaderRequest req(mesh_params);
   866 		pending_lod_map::iterator pending = mPendingLOD.find(mesh_params);
   868 		if (pending != mPendingLOD.end())
   869 		{ //append this lod request to existing header request
   870 			pending->second.push_back(lod);
   871 			llassert(pending->second.size() <= LLModel::NUM_LODS)
   872 		}
   873 		else
   874 		{ //if no header request is pending, fetch header
   875 			mHeaderReqQ.push(req);
   876 			mPendingLOD[mesh_params].push_back(lod);
   877 		}
   878 	}
   879 }
   881 // Constructs a Cap URL for the mesh.  Prefers a GetMesh2 cap
   882 // over a GetMesh cap.
   883 //
   884 //static 
   885 std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id)
   886 {
   887 	std::string http_url;
   889 	if (gAgent.getRegion())
   890 	{
   891 		if (! gMeshRepo.mGetMesh2Capability.empty())
   892 		{
   893 			http_url = gMeshRepo.mGetMesh2Capability;
   894 		}
   895 		else
   896 		{
   897 			http_url = gMeshRepo.mGetMeshCapability;
   898 		}
   899 	}
   901 	if (!http_url.empty())
   902 	{
   903 		http_url += "/?mesh_id=";
   904 		http_url += mesh_id.asString().c_str();
   905 	}
   906 	else
   907 	{
   908 		LL_WARNS_ONCE(LOG_MESH) << "Current region does not have GetMesh capability!  Cannot load "
   909 								<< mesh_id << ".mesh" << LL_ENDL;
   910 	}
   912 	return http_url;
   913 }
   915 // Issue an HTTP GET request with byte range using the right
   916 // policy class.  Large requests go to the large request class.
   917 // If the current region supports GetMesh2, we prefer that for
   918 // smaller requests otherwise we try to use the traditional
   919 // GetMesh capability and connection concurrency.
   920 //
   921 // @return		Valid handle or LLCORE_HTTP_HANDLE_INVALID.
   922 //				If the latter, actual status is found in
   923 //				mHttpStatus member which is valid until the
   924 //				next call to this method.
   925 //
   926 // Thread:  repo
   927 LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int cap_version,
   928 												  size_t offset, size_t len,
   929 												  LLCore::HttpHandler * handler)
   930 {
   931 	LLCore::HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
   933 	if (len < LARGE_MESH_FETCH_THRESHOLD)
   934 	{
   935 		handle = mHttpRequest->requestGetByteRange((2 == cap_version
   936 													? mHttpPolicyClass
   937 													: mHttpLegacyPolicyClass),
   938 												   mHttpPriority,
   939 												   url,
   940 												   offset,
   941 												   len,
   942 												   mHttpOptions,
   943 												   mHttpHeaders,
   944 												   handler);
   945 		++mHttpGetCount;
   946 	}
   947 	else
   948 	{
   949 		handle = mHttpRequest->requestGetByteRange(mHttpLargePolicyClass,
   950 												   mHttpPriority,
   951 												   url,
   952 												   offset,
   953 												   len,
   954 												   mHttpLargeOptions,
   955 												   mHttpHeaders,
   956 												   handler);
   957 		++mHttpLargeGetCount;
   958 	}
   959 	if (LLCORE_HTTP_HANDLE_INVALID == handle)
   960 	{
   961 		// Something went wrong, capture the error code for caller.
   962 		mHttpStatus = mHttpRequest->getStatus();
   963 	}
   964 	return handle;
   965 }
   968 bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, U32& count)
   969 {
   971 	if (!mHeaderMutex)
   972 	{
   973 		return false;
   974 	}
   976 	mHeaderMutex->lock();
   978 	if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
   979 	{ //we have no header info for this mesh, do nothing
   980 		mHeaderMutex->unlock();
   981 		return false;
   982 	}
   984 	bool ret = true ;
   985 	U32 header_size = mMeshHeaderSize[mesh_id];
   987 	if (header_size > 0)
   988 	{
   989 		S32 version = mMeshHeader[mesh_id]["version"].asInteger();
   990 		S32 offset = header_size + mMeshHeader[mesh_id]["skin"]["offset"].asInteger();
   991 		S32 size = mMeshHeader[mesh_id]["skin"]["size"].asInteger();
   993 		mHeaderMutex->unlock();
   995 		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
   996 		{
   997 			//check VFS for mesh skin info
   998 			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
   999 			if (file.getSize() >= offset+size)
  1001 				LLMeshRepository::sCacheBytesRead += size;
  1002 				file.seek(offset);
  1003 				U8* buffer = new U8[size];
  1004 				file.read(buffer, size);
  1006 				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
  1007 				bool zero = true;
  1008 				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
  1010 					zero = buffer[i] > 0 ? false : true;
  1013 				if (!zero)
  1014 				{ //attempt to parse
  1015 					if (skinInfoReceived(mesh_id, buffer, size))
  1017 						delete[] buffer;
  1018 						return true;
  1022 				delete[] buffer;
  1025 			//reading from VFS failed for whatever reason, fetch from sim
  1026 			if (count >= MAX_MESH_REQUESTS_PER_SECOND || mHttpRequestSet.size() >= sRequestHighWater)
  1028 				return false;
  1030 			int cap_version(gMeshRepo.mGetMeshVersion);
  1031 			std::string http_url = constructUrl(mesh_id);
  1032 			if (!http_url.empty())
  1034 				LLMeshSkinInfoHandler * handler = new LLMeshSkinInfoHandler(mesh_id, offset, size);
  1035 				LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
  1036 				if (LLCORE_HTTP_HANDLE_INVALID == handle)
  1038 					LL_WARNS(LOG_MESH) << "HTTP GET request failed for skin info on mesh " << mID
  1039 									   << ".  Reason:  " << mHttpStatus.toString()
  1040 									   << " (" << mHttpStatus.toHex() << ")"
  1041 									   << LL_ENDL;
  1042 					delete handler;
  1043 					ret = false;
  1045 				else
  1047 					handler->mHttpHandle = handle;
  1048 					mHttpRequestSet.insert(handler);
  1049 					++LLMeshRepository::sHTTPRequestCount;
  1054 	else
  1056 		mHeaderMutex->unlock();
  1059 	//early out was not hit, effectively fetched
  1060 	return ret;
  1063 bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id, U32& count)
  1065 	if (!mHeaderMutex)
  1067 		return false;
  1070 	mHeaderMutex->lock();
  1072 	if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
  1073 	{ //we have no header info for this mesh, do nothing
  1074 		mHeaderMutex->unlock();
  1075 		return false;
  1078 	U32 header_size = mMeshHeaderSize[mesh_id];
  1079 	bool ret = true ;
  1081 	if (header_size > 0)
  1083 		S32 version = mMeshHeader[mesh_id]["version"].asInteger();
  1084 		S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger();
  1085 		S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger();
  1087 		mHeaderMutex->unlock();
  1089 		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
  1091 			//check VFS for mesh skin info
  1092 			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
  1093 			if (file.getSize() >= offset+size)
  1095 				LLMeshRepository::sCacheBytesRead += size;
  1097 				file.seek(offset);
  1098 				U8* buffer = new U8[size];
  1099 				file.read(buffer, size);
  1101 				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
  1102 				bool zero = true;
  1103 				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
  1105 					zero = buffer[i] > 0 ? false : true;
  1108 				if (!zero)
  1109 				{ //attempt to parse
  1110 					if (decompositionReceived(mesh_id, buffer, size))
  1112 						delete[] buffer;
  1113 						return true;
  1117 				delete[] buffer;
  1120 			//reading from VFS failed for whatever reason, fetch from sim
  1121 			if (count >= MAX_MESH_REQUESTS_PER_SECOND || mHttpRequestSet.size() >= sRequestHighWater)
  1123 				return false;
  1125 			int cap_version(gMeshRepo.mGetMeshVersion);
  1126 			std::string http_url = constructUrl(mesh_id);
  1127 			if (!http_url.empty())
  1129 				LLMeshDecompositionHandler * handler = new LLMeshDecompositionHandler(mesh_id, offset, size);
  1130 				LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
  1131 				if (LLCORE_HTTP_HANDLE_INVALID == handle)
  1133 					LL_WARNS(LOG_MESH) << "HTTP GET request failed for decomposition mesh " << mID
  1134 									   << ".  Reason:  " << mHttpStatus.toString()
  1135 									   << " (" << mHttpStatus.toHex() << ")"
  1136 									   << LL_ENDL;
  1137 					delete handler;
  1138 					ret = false;
  1140 				else
  1142 					handler->mHttpHandle = handle;
  1143 					mHttpRequestSet.insert(handler);
  1144 					++LLMeshRepository::sHTTPRequestCount;
  1149 	else
  1151 		mHeaderMutex->unlock();
  1154 	//early out was not hit, effectively fetched
  1155 	return ret;
  1158 bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id, U32& count)
  1160 	if (!mHeaderMutex)
  1162 		return false;
  1165 	mHeaderMutex->lock();
  1167 	if (mMeshHeader.find(mesh_id) == mMeshHeader.end())
  1168 	{ //we have no header info for this mesh, do nothing
  1169 		mHeaderMutex->unlock();
  1170 		return false;
  1173 	U32 header_size = mMeshHeaderSize[mesh_id];
  1174 	bool ret = true ;
  1176 	if (header_size > 0)
  1178 		S32 version = mMeshHeader[mesh_id]["version"].asInteger();
  1179 		S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger();
  1180 		S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger();
  1182 		mHeaderMutex->unlock();
  1184 		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
  1186 			//check VFS for mesh physics shape info
  1187 			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
  1188 			if (file.getSize() >= offset+size)
  1190 				LLMeshRepository::sCacheBytesRead += size;
  1191 				file.seek(offset);
  1192 				U8* buffer = new U8[size];
  1193 				file.read(buffer, size);
  1195 				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
  1196 				bool zero = true;
  1197 				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
  1199 					zero = buffer[i] > 0 ? false : true;
  1202 				if (!zero)
  1203 				{ //attempt to parse
  1204 					if (physicsShapeReceived(mesh_id, buffer, size))
  1206 						delete[] buffer;
  1207 						return true;
  1211 				delete[] buffer;
  1214 			//reading from VFS failed for whatever reason, fetch from sim
  1215 			if (count >= MAX_MESH_REQUESTS_PER_SECOND || mHttpRequestSet.size() >= sRequestHighWater)
  1217 				return false;
  1219 			int cap_version(gMeshRepo.mGetMeshVersion);
  1220 			std::string http_url = constructUrl(mesh_id);
  1221 			if (!http_url.empty())
  1223 				LLMeshPhysicsShapeHandler * handler = new LLMeshPhysicsShapeHandler(mesh_id, offset, size);
  1224 				LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
  1225 				if (LLCORE_HTTP_HANDLE_INVALID == handle)
  1227 					LL_WARNS(LOG_MESH) << "HTTP GET request failed for physics shape on mesh " << mID
  1228 									   << ".  Reason:  " << mHttpStatus.toString()
  1229 									   << " (" << mHttpStatus.toHex() << ")"
  1230 									   << LL_ENDL;
  1231 					delete handler;
  1232 					ret = false;
  1234 				else
  1236 					handler->mHttpHandle = handle;
  1237 					mHttpRequestSet.insert(handler);
  1238 					++LLMeshRepository::sHTTPRequestCount;
  1242 		else
  1243 		{ //no physics shape whatsoever, report back NULL
  1244 			physicsShapeReceived(mesh_id, NULL, 0);
  1247 	else
  1249 		mHeaderMutex->unlock();
  1252 	//early out was not hit, effectively fetched
  1253 	return ret;
  1256 //static
  1257 void LLMeshRepoThread::incActiveLODRequests()
  1259 	LLMutexLock lock(gMeshRepo.mThread->mMutex);
  1260 	++LLMeshRepoThread::sActiveLODRequests;
  1263 //static
  1264 void LLMeshRepoThread::decActiveLODRequests()
  1266 	LLMutexLock lock(gMeshRepo.mThread->mMutex);
  1267 	--LLMeshRepoThread::sActiveLODRequests;
  1270 //static
  1271 void LLMeshRepoThread::incActiveHeaderRequests()
  1273 	LLMutexLock lock(gMeshRepo.mThread->mMutex);
  1274 	++LLMeshRepoThread::sActiveHeaderRequests;
  1277 //static
  1278 void LLMeshRepoThread::decActiveHeaderRequests()
  1280 	LLMutexLock lock(gMeshRepo.mThread->mMutex);
  1281 	--LLMeshRepoThread::sActiveHeaderRequests;
  1284 //return false if failed to get header
  1285 bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& count)
  1288 		//look for mesh in asset in vfs
  1289 		LLVFile file(gVFS, mesh_params.getSculptID(), LLAssetType::AT_MESH);
  1291 		S32 size = file.getSize();
  1293 		if (size > 0)
  1295 			// *NOTE:  if the header size is ever more than 4KB, this will break
  1296 			U8 buffer[MESH_HEADER_SIZE];
  1297 			S32 bytes = llmin(size, MESH_HEADER_SIZE);
  1298 			LLMeshRepository::sCacheBytesRead += bytes;	
  1299 			file.read(buffer, bytes);
  1300 			if (headerReceived(mesh_params, buffer, bytes))
  1302 				// Found mesh in VFS cache
  1303 				return true;
  1308 	//either cache entry doesn't exist or is corrupt, request header from simulator	
  1309 	bool retval = true;
  1310 	int cap_version(gMeshRepo.mGetMeshVersion);
  1311 	std::string http_url = constructUrl(mesh_params.getSculptID());
  1312 	if (!http_url.empty())
  1314 		//grab first 4KB if we're going to bother with a fetch.  Cache will prevent future fetches if a full mesh fits
  1315 		//within the first 4KB
  1316 		//NOTE -- this will break of headers ever exceed 4KB		
  1318 		LLMeshHeaderHandler * handler = new LLMeshHeaderHandler(mesh_params);
  1319 		LLCore::HttpHandle handle = getByteRange(http_url, cap_version, 0, MESH_HEADER_SIZE, handler);
  1320 		if (LLCORE_HTTP_HANDLE_INVALID == handle)
  1322 			LL_WARNS(LOG_MESH) << "HTTP GET request failed for mesh header " << mID
  1323 							   << ".  Reason:  " << mHttpStatus.toString()
  1324 							   << " (" << mHttpStatus.toHex() << ")"
  1325 							   << LL_ENDL;
  1326 			delete handler;
  1327 			retval = false;
  1329 		else
  1331 			handler->mHttpHandle = handle;
  1332 			mHttpRequestSet.insert(handler);
  1333 			++LLMeshRepository::sHTTPRequestCount;
  1334 			++count;
  1338 	return retval;
  1341 //return false if failed to get mesh lod.
  1342 bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count)
  1344 	if (!mHeaderMutex)
  1346 		return false;
  1349 	mHeaderMutex->lock();
  1351 	bool retval = true;
  1353 	LLUUID mesh_id = mesh_params.getSculptID();
  1355 	U32 header_size = mMeshHeaderSize[mesh_id];
  1357 	if (header_size > 0)
  1359 		S32 version = mMeshHeader[mesh_id]["version"].asInteger();
  1360 		S32 offset = header_size + mMeshHeader[mesh_id][header_lod[lod]]["offset"].asInteger();
  1361 		S32 size = mMeshHeader[mesh_id][header_lod[lod]]["size"].asInteger();
  1362 		mHeaderMutex->unlock();
  1364 		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0)
  1367 			//check VFS for mesh asset
  1368 			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH);
  1369 			if (file.getSize() >= offset+size)
  1371 				LLMeshRepository::sCacheBytesRead += size;
  1372 				file.seek(offset);
  1373 				U8* buffer = new U8[size];
  1374 				file.read(buffer, size);
  1376 				//make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written)
  1377 				bool zero = true;
  1378 				for (S32 i = 0; i < llmin(size, 1024) && zero; ++i)
  1380 					zero = buffer[i] > 0 ? false : true;
  1383 				if (!zero)
  1384 				{ //attempt to parse
  1385 					if (lodReceived(mesh_params, lod, buffer, size))
  1387 						delete[] buffer;
  1388 						return true;
  1392 				delete[] buffer;
  1395 			//reading from VFS failed for whatever reason, fetch from sim
  1396 			int cap_version(gMeshRepo.mGetMeshVersion);
  1397 			std::string http_url = constructUrl(mesh_id);
  1398 			if (!http_url.empty())
  1400 				LLMeshLODHandler * handler = new LLMeshLODHandler(mesh_params, lod, offset, size);
  1401 				LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);
  1402 				if (LLCORE_HTTP_HANDLE_INVALID == handle)
  1404 					LL_WARNS(LOG_MESH) << "HTTP GET request failed for LOD on mesh " << mID
  1405 									   << ".  Reason:  " << mHttpStatus.toString()
  1406 									   << " (" << mHttpStatus.toHex() << ")"
  1407 									   << LL_ENDL;
  1408 					delete handler;
  1409 					retval = false;
  1411 				else
  1413 					handler->mHttpHandle = handle;
  1414 					mHttpRequestSet.insert(handler);
  1415 					++LLMeshRepository::sHTTPRequestCount;
  1416 					++count;
  1419 			else
  1421 				mUnavailableQ.push(LODRequest(mesh_params, lod));
  1424 		else
  1426 			mUnavailableQ.push(LODRequest(mesh_params, lod));
  1429 	else
  1431 		mHeaderMutex->unlock();
  1434 	return retval;
  1437 bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size)
  1439 	const LLUUID mesh_id = mesh_params.getSculptID();
  1440 	LLSD header;
  1442 	U32 header_size = 0;
  1443 	if (data_size > 0)
  1445 		std::string res_str((char*) data, data_size);
  1447 		std::string deprecated_header("<? LLSD/Binary ?>");
  1449 		if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
  1451 			res_str = res_str.substr(deprecated_header.size()+1, data_size);
  1452 			header_size = deprecated_header.size()+1;
  1454 		data_size = res_str.size();
  1456 		std::istringstream stream(res_str);
  1458 		if (!LLSDSerialize::fromBinary(header, stream, data_size))
  1460 			LL_WARNS(LOG_MESH) << "Mesh header parse error.  Not a valid mesh asset!  ID:  " << mesh_id
  1461 							   << LL_ENDL;
  1462 			return false;
  1465 		header_size += stream.tellg();
  1467 	else
  1469 		LL_INFOS(LOG_MESH) << "Non-positive data size.  Marking header as non-existent, will not retry.  ID:  " << mesh_id
  1470 						   << LL_ENDL;
  1471 		header["404"] = 1;
  1477 			LLMutexLock lock(mHeaderMutex);
  1478 			mMeshHeaderSize[mesh_id] = header_size;
  1479 			mMeshHeader[mesh_id] = header;
  1483 		LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time.
  1485 		//check for pending requests
  1486 		pending_lod_map::iterator iter = mPendingLOD.find(mesh_params);
  1487 		if (iter != mPendingLOD.end())
  1489 			for (U32 i = 0; i < iter->second.size(); ++i)
  1491 				LODRequest req(mesh_params, iter->second[i]);
  1492 				mLODReqQ.push(req);
  1493 				LLMeshRepository::sLODProcessing++;
  1495 			mPendingLOD.erase(iter);
  1499 	return true;
  1502 bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size)
  1504 	LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod));
  1505 	std::string mesh_string((char*) data, data_size);
  1506 	std::istringstream stream(mesh_string);
  1508 	if (volume->unpackVolumeFaces(stream, data_size))
  1510 		if (volume->getNumFaces() > 0)
  1512 			LoadedMesh mesh(volume, mesh_params, lod);
  1514 				LLMutexLock lock(mMutex);
  1515 				mLoadedQ.push(mesh);
  1517 			return true;
  1521 	return false;
  1524 bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size)
  1526 	LLSD skin;
  1528 	if (data_size > 0)
  1530 		std::string res_str((char*) data, data_size);
  1532 		std::istringstream stream(res_str);
  1534 		if (!unzip_llsd(skin, stream, data_size))
  1536 			LL_WARNS(LOG_MESH) << "Mesh skin info parse error.  Not a valid mesh asset!  ID:  " << mesh_id
  1537 							   << LL_ENDL;
  1538 			return false;
  1543 		LLMeshSkinInfo info(skin);
  1544 		info.mMeshID = mesh_id;
  1546 		// LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL;
  1547 		mSkinInfoQ.push(info);
  1550 	return true;
  1553 bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size)
  1555 	LLSD decomp;
  1557 	if (data_size > 0)
  1559 		std::string res_str((char*) data, data_size);
  1561 		std::istringstream stream(res_str);
  1563 		if (!unzip_llsd(decomp, stream, data_size))
  1565 			LL_WARNS(LOG_MESH) << "Mesh decomposition parse error.  Not a valid mesh asset!  ID:  " << mesh_id
  1566 							   << LL_ENDL;
  1567 			return false;
  1572 		LLModel::Decomposition* d = new LLModel::Decomposition(decomp);
  1573 		d->mMeshID = mesh_id;
  1574 		mDecompositionQ.push(d);
  1577 	return true;
  1580 bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size)
  1582 	LLSD physics_shape;
  1584 	LLModel::Decomposition* d = new LLModel::Decomposition();
  1585 	d->mMeshID = mesh_id;
  1587 	if (data == NULL)
  1588 	{ //no data, no physics shape exists
  1589 		d->mPhysicsShapeMesh.clear();
  1591 	else
  1593 		LLVolumeParams volume_params;
  1594 		volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
  1595 		volume_params.setSculptID(mesh_id, LL_SCULPT_TYPE_MESH);
  1596 		LLPointer<LLVolume> volume = new LLVolume(volume_params,0);
  1597 		std::string mesh_string((char*) data, data_size);
  1598 		std::istringstream stream(mesh_string);
  1600 		if (volume->unpackVolumeFaces(stream, data_size))
  1602 			//load volume faces into decomposition buffer
  1603 			S32 vertex_count = 0;
  1604 			S32 index_count = 0;
  1606 			for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
  1608 				const LLVolumeFace& face = volume->getVolumeFace(i);
  1609 				vertex_count += face.mNumVertices;
  1610 				index_count += face.mNumIndices;
  1613 			d->mPhysicsShapeMesh.clear();
  1615 			std::vector<LLVector3>& pos = d->mPhysicsShapeMesh.mPositions;
  1616 			std::vector<LLVector3>& norm = d->mPhysicsShapeMesh.mNormals;
  1618 			for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
  1620 				const LLVolumeFace& face = volume->getVolumeFace(i);
  1622 				for (S32 i = 0; i < face.mNumIndices; ++i)
  1624 					U16 idx = face.mIndices[i];
  1626 					pos.push_back(LLVector3(face.mPositions[idx].getF32ptr()));
  1627 					norm.push_back(LLVector3(face.mNormals[idx].getF32ptr()));				
  1633 	mDecompositionQ.push(d);
  1634 	return true;
  1638 LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures,
  1639 									   bool upload_skin, bool upload_joints, const std::string & upload_url, bool do_upload,
  1640 									   LLHandle<LLWholeModelFeeObserver> fee_observer,
  1641 									   LLHandle<LLWholeModelUploadObserver> upload_observer)
  1642   : LLThread("mesh upload"),
  1643 	LLCore::HttpHandler(),
  1644 	mDiscarded(FALSE),
  1645 	mDoUpload(do_upload),
  1646 	mWholeModelUploadURL(upload_url),
  1647 	mFeeObserverHandle(fee_observer),
  1648 	mUploadObserverHandle(upload_observer)
  1650 	mInstanceList = data;
  1651 	mUploadTextures = upload_textures;
  1652 	mUploadSkin = upload_skin;
  1653 	mUploadJoints = upload_joints;
  1654 	mMutex = new LLMutex(NULL);
  1655 	mPendingUploads = 0;
  1656 	mFinished = false;
  1657 	mOrigin = gAgent.getPositionAgent();
  1658 	mHost = gAgent.getRegionHost();
  1660 	mWholeModelFeeCapability = gAgent.getRegion()->getCapability("NewFileAgentInventory");
  1662 	mOrigin += gAgent.getAtAxis() * scale.magVec();
  1664 	mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut");
  1666 	mHttpRequest = new LLCore::HttpRequest;
  1667 	mHttpOptions = new LLCore::HttpOptions;
  1668 	mHttpOptions->setTransferTimeout(mMeshUploadTimeOut);
  1669 	mHttpHeaders = new LLCore::HttpHeaders;
  1670 	mHttpHeaders->append("Content-Type", "application/llsd+xml");
  1671 	mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicy(LLAppCoreHttp::AP_UPLOADS);
  1672 	mHttpPriority = 0;
  1675 LLMeshUploadThread::~LLMeshUploadThread()
  1677 	if (mHttpHeaders)
  1679 		mHttpHeaders->release();
  1680 		mHttpHeaders = NULL;
  1682 	if (mHttpOptions)
  1684 		mHttpOptions->release();
  1685 		mHttpOptions = NULL;
  1687 	delete mHttpRequest;
  1688 	mHttpRequest = NULL;
  1691 LLMeshUploadThread::DecompRequest::DecompRequest(LLModel* mdl, LLModel* base_model, LLMeshUploadThread* thread)
  1693 	mStage = "single_hull";
  1694 	mModel = mdl;
  1695 	mDecompID = &mdl->mDecompID;
  1696 	mBaseModel = base_model;
  1697 	mThread = thread;
  1699 	//copy out positions and indices
  1700 	assignData(mdl) ;	
  1702 	mThread->mFinalDecomp = this;
  1703 	mThread->mPhysicsComplete = false;
  1706 void LLMeshUploadThread::DecompRequest::completed()
  1708 	if (mThread->mFinalDecomp == this)
  1710 		mThread->mPhysicsComplete = true;
  1713 	llassert(mHull.size() == 1);
  1715 	mThread->mHullMap[mBaseModel] = mHull[0];
  1718 //called in the main thread.
  1719 void LLMeshUploadThread::preStart()
  1721 	//build map of LLModel refs to instances for callbacks
  1722 	for (instance_list::iterator iter = mInstanceList.begin(); iter != mInstanceList.end(); ++iter)
  1724 		mInstance[iter->mModel].push_back(*iter);
  1728 void LLMeshUploadThread::discard()
  1730 	LLMutexLock lock(mMutex);
  1731 	mDiscarded = TRUE;
  1734 BOOL LLMeshUploadThread::isDiscarded() const
  1736 	LLMutexLock lock(mMutex);
  1737 	return mDiscarded;
  1740 void LLMeshUploadThread::run()
  1742 	if (mDoUpload)
  1744 		doWholeModelUpload();
  1746 	else
  1748 		requestWholeModelFee();
  1752 void dump_llsd_to_file(const LLSD& content, std::string filename)
  1754 	if (gSavedSettings.getBOOL("MeshUploadLogXML"))
  1756 		std::ofstream of(filename.c_str());
  1757 		LLSDSerialize::toPrettyXML(content,of);
  1761 LLSD llsd_from_file(std::string filename)
  1763 	std::ifstream ifs(filename.c_str());
  1764 	LLSD result;
  1765 	LLSDSerialize::fromXML(result,ifs);
  1766 	return result;
  1769 void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
  1771 	LLSD result;
  1773 	LLSD res;
  1774 	result["folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
  1775 	result["texture_folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE);
  1776 	result["asset_type"] = "mesh";
  1777 	result["inventory_type"] = "object";
  1778 	result["description"] = "(No Description)";
  1779 	result["next_owner_mask"] = LLSD::Integer(LLFloaterPerms::getNextOwnerPerms());
  1780 	result["group_mask"] = LLSD::Integer(LLFloaterPerms::getGroupPerms());
  1781 	result["everyone_mask"] = LLSD::Integer(LLFloaterPerms::getEveryonePerms());
  1783 	res["mesh_list"] = LLSD::emptyArray();
  1784 	res["texture_list"] = LLSD::emptyArray();
  1785 	res["instance_list"] = LLSD::emptyArray();
  1786 	S32 mesh_num = 0;
  1787 	S32 texture_num = 0;
  1789 	std::set<LLViewerTexture* > textures;
  1790 	std::map<LLViewerTexture*,S32> texture_index;
  1792 	std::map<LLModel*,S32> mesh_index;
  1793 	std::string model_name;
  1794 	std::string model_metric;
  1796 	S32 instance_num = 0;
  1798 	for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
  1800 		LLMeshUploadData data;
  1801 		data.mBaseModel = iter->first;
  1802 		LLModelInstance& first_instance = *(iter->second.begin());
  1803 		for (S32 i = 0; i < 5; i++)
  1805 			data.mModel[i] = first_instance.mLOD[i];
  1808 		if (mesh_index.find(data.mBaseModel) == mesh_index.end())
  1810 			// Have not seen this model before - create a new mesh_list entry for it.
  1811 			if (model_name.empty())
  1813 				model_name = data.mBaseModel->getName();
  1816 			if (model_metric.empty())
  1818 				model_metric = data.mBaseModel->getMetric();
  1821 			std::stringstream ostr;
  1823 			LLModel::Decomposition& decomp =
  1824 				data.mModel[LLModel::LOD_PHYSICS].notNull() ? 
  1825 				data.mModel[LLModel::LOD_PHYSICS]->mPhysics : 
  1826 				data.mBaseModel->mPhysics;
  1828 			decomp.mBaseHull = mHullMap[data.mBaseModel];
  1830 			LLSD mesh_header = LLModel::writeModel(
  1831 				ostr,  
  1832 				data.mModel[LLModel::LOD_PHYSICS],
  1833 				data.mModel[LLModel::LOD_HIGH],
  1834 				data.mModel[LLModel::LOD_MEDIUM],
  1835 				data.mModel[LLModel::LOD_LOW],
  1836 				data.mModel[LLModel::LOD_IMPOSTOR], 
  1837 				decomp,
  1838 				mUploadSkin,
  1839 				mUploadJoints);
  1841 			data.mAssetData = ostr.str();
  1842 			std::string str = ostr.str();
  1844 			res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(),str.end()); 
  1845 			mesh_index[data.mBaseModel] = mesh_num;
  1846 			mesh_num++;
  1849 		// For all instances that use this model
  1850 		for (instance_list::iterator instance_iter = iter->second.begin();
  1851 			 instance_iter != iter->second.end();
  1852 			 ++instance_iter)
  1855 			LLModelInstance& instance = *instance_iter;
  1857 			LLSD instance_entry;
  1859 			for (S32 i = 0; i < 5; i++)
  1861 				data.mModel[i] = instance.mLOD[i];
  1864 			LLVector3 pos, scale;
  1865 			LLQuaternion rot;
  1866 			LLMatrix4 transformation = instance.mTransform;
  1867 			decomposeMeshMatrix(transformation,pos,rot,scale);
  1868 			instance_entry["position"] = ll_sd_from_vector3(pos);
  1869 			instance_entry["rotation"] = ll_sd_from_quaternion(rot);
  1870 			instance_entry["scale"] = ll_sd_from_vector3(scale);
  1872 			instance_entry["material"] = LL_MCODE_WOOD;
  1873 			instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
  1874 			instance_entry["mesh"] = mesh_index[data.mBaseModel];
  1876 			instance_entry["face_list"] = LLSD::emptyArray();
  1878 			S32 end = llmin((S32)data.mBaseModel->mMaterialList.size(), data.mBaseModel->getNumVolumeFaces()) ;
  1879 			for (S32 face_num = 0; face_num < end; face_num++)
  1881 				LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];
  1882 				LLSD face_entry = LLSD::emptyMap();
  1883 				LLViewerFetchedTexture *texture = material.mDiffuseMap.get();
  1885 				if ((texture != NULL) &&
  1886 					(textures.find(texture) == textures.end()))
  1888 					textures.insert(texture);
  1891 				std::stringstream texture_str;
  1892 				if (texture != NULL && include_textures && mUploadTextures)
  1894 					if(texture->hasSavedRawImage())
  1896 						LLPointer<LLImageJ2C> upload_file =
  1897 							LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());
  1898 						texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
  1902 				if (texture != NULL &&
  1903 					mUploadTextures &&
  1904 					texture_index.find(texture) == texture_index.end())
  1906 					texture_index[texture] = texture_num;
  1907 					std::string str = texture_str.str();
  1908 					res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
  1909 					texture_num++;
  1912 				// Subset of TextureEntry fields.
  1913 				if (texture != NULL && mUploadTextures)
  1915 					face_entry["image"] = texture_index[texture];
  1916 					face_entry["scales"] = 1.0;
  1917 					face_entry["scalet"] = 1.0;
  1918 					face_entry["offsets"] = 0.0;
  1919 					face_entry["offsett"] = 0.0;
  1920 					face_entry["imagerot"] = 0.0;
  1922 				face_entry["diffuse_color"] = ll_sd_from_color4(material.mDiffuseColor);
  1923 				face_entry["fullbright"] = material.mFullbright;
  1924 				instance_entry["face_list"][face_num] = face_entry;
  1927 			res["instance_list"][instance_num] = instance_entry;
  1928 			instance_num++;
  1932 	if (model_name.empty()) model_name = "mesh model";
  1933 	result["name"] = model_name;
  1934 	if (model_metric.empty()) model_metric = "MUT_Unspecified";
  1935 	res["metric"] = model_metric;
  1936 	result["asset_resources"] = res;
  1937 	dump_llsd_to_file(result,make_dump_name("whole_model_",dump_num));
  1939 	dest = result;
  1942 void LLMeshUploadThread::generateHulls()
  1944 	bool has_valid_requests = false ;
  1946 	for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter)
  1948 		LLMeshUploadData data;
  1949 		data.mBaseModel = iter->first;
  1951 		LLModelInstance& instance = *(iter->second.begin());
  1953 		for (S32 i = 0; i < 5; i++)
  1955 			data.mModel[i] = instance.mLOD[i];
  1958 		//queue up models for hull generation
  1959 		LLModel* physics = NULL;
  1961 		if (data.mModel[LLModel::LOD_PHYSICS].notNull())
  1963 			physics = data.mModel[LLModel::LOD_PHYSICS];
  1965 		else if (data.mModel[LLModel::LOD_LOW].notNull())
  1967 			physics = data.mModel[LLModel::LOD_LOW];
  1969 		else if (data.mModel[LLModel::LOD_MEDIUM].notNull())
  1971 			physics = data.mModel[LLModel::LOD_MEDIUM];
  1973 		else
  1975 			physics = data.mModel[LLModel::LOD_HIGH];
  1978 		llassert(physics != NULL);
  1980 		DecompRequest* request = new DecompRequest(physics, data.mBaseModel, this);
  1981 		if(request->isValid())
  1983 			gMeshRepo.mDecompThread->submitRequest(request);
  1984 			has_valid_requests = true ;
  1988 	if (has_valid_requests)
  1990 		while (!mPhysicsComplete)
  1992 			apr_sleep(100);
  1997 void LLMeshUploadThread::doWholeModelUpload()
  1999 	LL_DEBUGS(LOG_MESH) << "Starting model upload.  Instances:  " << mInstance.size() << LL_ENDL;
  2001 	if (mWholeModelUploadURL.empty())
  2003 		LL_WARNS(LOG_MESH) << "Missing mesh upload capability, unable to upload, fee request failed."
  2004 						   << LL_ENDL;
  2006 	else
  2008 		generateHulls();
  2009 		LL_DEBUGS(LOG_MESH) << "Hull generation completed." << LL_ENDL;
  2011 		mModelData = LLSD::emptyMap();
  2012 		wholeModelToLLSD(mModelData, true);
  2013 		LLSD body = mModelData["asset_resources"];
  2014 		dump_llsd_to_file(body, make_dump_name("whole_model_body_", dump_num));
  2016 		LLCore::BufferArray * ba = new LLCore::BufferArray;
  2017 		LLCore::BufferArrayStream bas(ba);
  2018 		LLSDSerialize::toXML(body, bas);
  2019 		// LLSDSerialize::toXML(mModelData, bas);		// <- This will generate a convenient upload error
  2020 		LLCore::HttpHandle handle = mHttpRequest->requestPost(mHttpPolicyClass,
  2021 															  mHttpPriority,
  2022 															  mWholeModelUploadURL,
  2023 															  ba,
  2024 															  mHttpOptions,
  2025 															  mHttpHeaders,
  2026 															  this);
  2027 		ba->release();
  2029 		if (LLCORE_HTTP_HANDLE_INVALID == handle)
  2031 			mHttpStatus = mHttpRequest->getStatus();
  2033 			LL_WARNS(LOG_MESH) << "Couldn't issue request for full model upload.  Reason:  " << mHttpStatus.toString()
  2034 							   << " (" << mHttpStatus.toHex() << ")"
  2035 							   << LL_ENDL;
  2037 		else
  2039 			U32 sleep_time(10);
  2041 			LL_DEBUGS(LOG_MESH) << "POST request issued." << LL_ENDL;
  2043 			mHttpRequest->update(0);
  2044 			while (! LLApp::isQuitting() && ! mFinished)
  2046 				ms_sleep(sleep_time);
  2047 				sleep_time = llmin(250U, sleep_time + sleep_time);
  2048 				mHttpRequest->update(0);
  2050 			LL_DEBUGS(LOG_MESH) << "Mesh upload operation completed." << LL_ENDL;
  2055 void LLMeshUploadThread::requestWholeModelFee()
  2057 	dump_num++;
  2059 	generateHulls();
  2061 	mModelData = LLSD::emptyMap();
  2062 	wholeModelToLLSD(mModelData, false);
  2063 	dump_llsd_to_file(mModelData, make_dump_name("whole_model_fee_request_", dump_num));
  2065 	LLCore::BufferArray * ba = new LLCore::BufferArray;
  2066 	LLCore::BufferArrayStream bas(ba);
  2067 	LLSDSerialize::toXML(mModelData, bas);
  2069 	LLCore::HttpHandle handle = mHttpRequest->requestPost(mHttpPolicyClass,
  2070 														  mHttpPriority,
  2071 														  mWholeModelFeeCapability,
  2072 														  ba,
  2073 														  mHttpOptions,
  2074 														  mHttpHeaders,
  2075 														  this);
  2076 	ba->release();
  2077 	if (LLCORE_HTTP_HANDLE_INVALID == handle)
  2079 		mHttpStatus = mHttpRequest->getStatus();
  2081 		LL_WARNS(LOG_MESH) << "Couldn't issue request for model fee.  Reason:  " << mHttpStatus.toString()
  2082 						   << " (" << mHttpStatus.toHex() << ")"
  2083 						   << LL_ENDL;
  2085 	else
  2087 		U32 sleep_time(10);
  2089 		mHttpRequest->update(0);
  2090 		while (! LLApp::isQuitting() && ! mFinished)
  2092 			ms_sleep(sleep_time);
  2093 			sleep_time = llmin(250U, sleep_time + sleep_time);
  2094 			mHttpRequest->update(0);
  2100 // Does completion duty for both fee queries and actual uploads.
  2101 void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
  2103 	// QA/Devel:  0x2 to enable fake error import on upload, 0x1 on fee check
  2104 	const S32 fake_error(gSavedSettings.getS32("MeshUploadFakeErrors") & (mDoUpload ? 0xa : 0x5));
  2105 	LLCore::HttpStatus status(response->getStatus());
  2106 	if (fake_error)
  2108 		status = (fake_error & 0x0c) ? LLCore::HttpStatus(500) : LLCore::HttpStatus(200);
  2110 	std::string reason(status.toString());
  2111 	LLSD body;
  2113 	mFinished = true;
  2115 	if (mDoUpload)
  2117 		// model upload case
  2118 		LLWholeModelUploadObserver * observer(mUploadObserverHandle.get());
  2120 		if (! status)
  2122 			LL_WARNS(LOG_MESH) << "Upload failed.  Reason:  " << reason
  2123 							   << " (" << status.toHex() << ")"
  2124 							   << LL_ENDL;
  2126 			// Build a fake body for the alert generator
  2127 			body["error"] = LLSD::emptyMap();
  2128 			body["error"]["message"] = reason;
  2129 			body["error"]["identifier"] = "NetworkError";		// from asset-upload/upload_util.py
  2130 			log_upload_error(status, body, "upload", mModelData["name"].asString());
  2132 			if (observer)
  2134 				doOnIdleOneTime(boost::bind(&LLWholeModelUploadObserver::onModelUploadFailure, observer));
  2137 		else
  2139 			if (fake_error & 0x2)
  2141 				body = llsd_from_file("fake_upload_error.xml");
  2143 			else
  2145 				LLCore::BufferArray * ba(response->getBody());
  2146 				if (ba && ba->size())
  2148 					LLCore::BufferArrayStream bas(ba);
  2149 					LLSDSerialize::fromXML(body, bas);
  2152 			dump_llsd_to_file(body, make_dump_name("whole_model_upload_response_", dump_num));
  2154 			if (body["state"].asString() == "complete")
  2156 				// requested "mesh" asset type isn't actually the type
  2157 				// of the resultant object, fix it up here.
  2158 				mModelData["asset_type"] = "object";
  2159 				gMeshRepo.updateInventory(LLMeshRepository::inventory_data(mModelData, body));
  2161 				if (observer)
  2163 					doOnIdleOneTime(boost::bind(&LLWholeModelUploadObserver::onModelUploadSuccess, observer));
  2166 			else
  2168 				LL_WARNS(LOG_MESH) << "Upload failed.  Not in expected 'complete' state." << LL_ENDL;
  2169 				log_upload_error(status, body, "upload", mModelData["name"].asString());
  2171 				if (observer)
  2173 					doOnIdleOneTime(boost::bind(&LLWholeModelUploadObserver::onModelUploadFailure, observer));
  2178 	else
  2180 		// model fee case
  2181 		LLWholeModelFeeObserver* observer(mFeeObserverHandle.get());
  2182 		mWholeModelUploadURL.clear();
  2184 		if (! status)
  2186 			LL_WARNS(LOG_MESH) << "Fee request failed.  Reason:  " << reason
  2187 							   << " (" << status.toHex() << ")"
  2188 							   << LL_ENDL;
  2190 			// Build a fake body for the alert generator
  2191 			body["error"] = LLSD::emptyMap();
  2192 			body["error"]["message"] = reason;
  2193 			body["error"]["identifier"] = "NetworkError";		// from asset-upload/upload_util.py
  2194 			log_upload_error(status, body, "fee", mModelData["name"].asString());
  2196 			if (observer)
  2198 				observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason);
  2201 		else
  2203 			if (fake_error & 0x1)
  2205 				body = llsd_from_file("fake_upload_error.xml");
  2207 			else
  2209 				LLCore::BufferArray * ba(response->getBody());
  2210 				if (ba && ba->size())
  2212 					LLCore::BufferArrayStream bas(ba);
  2213 					LLSDSerialize::fromXML(body, bas);
  2216 			dump_llsd_to_file(body, make_dump_name("whole_model_fee_response_", dump_num));
  2218 			if (body["state"].asString() == "upload")
  2220 				mWholeModelUploadURL = body["uploader"].asString();
  2222 				if (observer)
  2224 					body["data"]["upload_price"] = body["upload_price"];
  2225 					observer->onModelPhysicsFeeReceived(body["data"], mWholeModelUploadURL);
  2228 			else
  2230 				LL_WARNS(LOG_MESH) << "Fee request failed.  Not in expected 'upload' state." << LL_ENDL;
  2231 				log_upload_error(status, body, "fee", mModelData["name"].asString());
  2233 				if (observer)
  2235 					observer->setModelPhysicsFeeErrorStatus(status.toULong(), reason);
  2243 void LLMeshRepoThread::notifyLoadedMeshes()
  2245 	if (!mMutex)
  2247 		return;
  2250 	if (!mLoadedQ.empty() || !mUnavailableQ.empty())
  2252 		// Ping time-to-load metrics for mesh download operations.
  2253 		LLMeshRepository::metricsProgress(0);
  2256 	while (!mLoadedQ.empty())
  2258 		mMutex->lock();
  2259 		LoadedMesh mesh = mLoadedQ.front();
  2260 		mLoadedQ.pop();
  2261 		mMutex->unlock();
  2263 		if (mesh.mVolume && mesh.mVolume->getNumVolumeFaces() > 0)
  2265 			gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume);
  2267 		else
  2269 			gMeshRepo.notifyMeshUnavailable(mesh.mMeshParams, 
  2270 				LLVolumeLODGroup::getVolumeDetailFromScale(mesh.mVolume->getDetail()));
  2274 	while (!mUnavailableQ.empty())
  2276 		mMutex->lock();
  2277 		LODRequest req = mUnavailableQ.front();
  2278 		mUnavailableQ.pop();
  2279 		mMutex->unlock();
  2281 		gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD);
  2284 	while (!mSkinInfoQ.empty())
  2286 		gMeshRepo.notifySkinInfoReceived(mSkinInfoQ.front());
  2287 		mSkinInfoQ.pop();
  2290 	while (!mDecompositionQ.empty())
  2292 		gMeshRepo.notifyDecompositionReceived(mDecompositionQ.front());
  2293 		mDecompositionQ.pop();
  2297 S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod) 
  2298 { //only ever called from main thread
  2299 	LLMutexLock lock(mHeaderMutex);
  2300 	mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID());
  2302 	if (iter != mMeshHeader.end())
  2304 		LLSD& header = iter->second;
  2306 		return LLMeshRepository::getActualMeshLOD(header, lod);
  2309 	return lod;
  2312 //static
  2313 S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod)
  2315 	lod = llclamp(lod, 0, 3);
  2317 	S32 version = header["version"];
  2319 	if (header.has("404") || version > MAX_MESH_VERSION)
  2321 		return -1;
  2324 	if (header[header_lod[lod]]["size"].asInteger() > 0)
  2326 		return lod;
  2329 	//search down to find the next available lower lod
  2330 	for (S32 i = lod-1; i >= 0; --i)
  2332 		if (header[header_lod[i]]["size"].asInteger() > 0)
  2334 			return i;
  2338 	//search up to find then ext available higher lod
  2339 	for (S32 i = lod+1; i < 4; ++i)
  2341 		if (header[header_lod[i]]["size"].asInteger() > 0)
  2343 			return i;
  2347 	//header exists and no good lod found, treat as 404
  2348 	header["404"] = 1;
  2349 	return -1;
  2352 void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)
  2354 	mThread->mMeshHeader[data.mUUID] = header;
  2356 	// we cache the mesh for default parameters
  2357 	LLVolumeParams volume_params;
  2358 	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
  2359 	volume_params.setSculptID(data.mUUID, LL_SCULPT_TYPE_MESH);
  2361 	for (U32 i = 0; i < 4; i++)
  2363 		if (data.mModel[i].notNull())
  2365 			LLPointer<LLVolume> volume = new LLVolume(volume_params, LLVolumeLODGroup::getVolumeScaleFromDetail(i));
  2366 			volume->copyVolumeFaces(data.mModel[i]);
  2367 			volume->setMeshAssetLoaded(TRUE);
  2373 void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
  2375 	mProcessed = true;
  2377 	// Accumulate retries, we'll use these to offset the HTTP
  2378 	// count and maybe hold to a throttle better.
  2379 	unsigned int retries(0U);
  2380 	response->getRetries(NULL, &retries);
  2381 	gMeshRepo.mThread->mHttpRetries += retries;
  2382 	LLMeshRepository::sHTTPRetryCount += retries;
  2384 	LLCore::HttpStatus status(response->getStatus());
  2385 	if (! status)
  2387 		processFailure(status);
  2389 	else
  2391 		// From texture fetch code and applies here:
  2392 		//
  2393 		// A warning about partial (HTTP 206) data.  Some grid services
  2394 		// do *not* return a 'Content-Range' header in the response to
  2395 		// Range requests with a 206 status.  We're forced to assume
  2396 		// we get what we asked for in these cases until we can fix
  2397 		// the services.
  2398 		static const LLCore::HttpStatus par_status(HTTP_PARTIAL_CONTENT);
  2400 		LLCore::BufferArray * body(response->getBody());
  2401 		S32 data_size(body ? body->size() : 0);
  2402 		U8 * data(NULL);
  2404 		if (data_size > 0)
  2406 			// *TODO: Try to get rid of data copying and add interfaces
  2407 			// that support BufferArray directly.
  2408 			data = new U8[data_size];
  2409 			body->read(0, (char *) data, data_size);
  2410 			LLMeshRepository::sBytesReceived += data_size;
  2413 		processData(body, data, data_size);
  2415 		delete [] data;
  2418 	// Release handler
  2419 	gMeshRepo.mThread->mHttpRequestSet.erase(this);
  2420 	delete this;		// Must be last statement
  2424 LLMeshHeaderHandler::~LLMeshHeaderHandler()
  2426 	if (!LLApp::isQuitting())
  2428 		if (! mProcessed)
  2430 			// something went wrong, retry
  2431 			LL_WARNS(LOG_MESH) << "Mesh header fetch canceled unexpectedly, retrying." << LL_ENDL;
  2432 			LLMeshRepoThread::HeaderRequest req(mMeshParams);
  2433 			LLMutexLock lock(gMeshRepo.mThread->mMutex);
  2434 			gMeshRepo.mThread->mHeaderReqQ.push(req);
  2436 		LLMeshRepoThread::decActiveHeaderRequests();
  2440 void LLMeshHeaderHandler::processFailure(LLCore::HttpStatus status)
  2442 	if (is_retryable(status))
  2444 		LL_WARNS(LOG_MESH) << "Error during mesh header handling.  Reason:  " << status.toString()
  2445 						   << " (" << status.toHex() << ").  Retrying."
  2446 						   << LL_ENDL;
  2447 		LLMeshRepoThread::HeaderRequest req(mMeshParams);
  2448 		LLMutexLock lock(gMeshRepo.mThread->mMutex);
  2449 		gMeshRepo.mThread->mHeaderReqQ.push(req);
  2451 	else
  2453 		// *TODO:  Mark mesh unavailable
  2454 		LL_WARNS(LOG_MESH) << "Error during mesh header handling.  Reason:  " << status.toString()
  2455 						   << " (" << status.toHex() << ").  Not retrying."
  2456 						   << LL_ENDL;
  2460 void LLMeshHeaderHandler::processData(LLCore::BufferArray * body, U8 * data, S32 data_size)
  2462 	LLUUID mesh_id = mMeshParams.getSculptID();
  2463 	bool success = gMeshRepo.mThread->headerReceived(mMeshParams, data, data_size);
  2464 	llassert(success);
  2465 	if (! success)
  2467 		// *TODO:  Mark mesh unavailable
  2468 		// *TODO:  Get real reason for parse failure here
  2469 		LL_WARNS(LOG_MESH) << "Unable to parse mesh header.  ID:  " << mesh_id
  2470 						   << LL_ENDL;
  2472 	else if (data && data_size > 0)
  2474 		// header was successfully retrieved from sim, cache in vfs
  2475 		LLSD header = gMeshRepo.mThread->mMeshHeader[mesh_id];
  2477 		S32 version = header["version"].asInteger();
  2479 		if (version <= MAX_MESH_VERSION)
  2481 			std::stringstream str;
  2483 			S32 lod_bytes = 0;
  2485 			for (U32 i = 0; i < LLModel::LOD_PHYSICS; ++i)
  2487 				// figure out how many bytes we'll need to reserve in the file
  2488 				const std::string & lod_name = header_lod[i];
  2489 				lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger());
  2492 			// just in case skin info or decomposition is at the end of the file (which it shouldn't be)
  2493 			lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger());
  2494 			lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger());
  2496 			S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id];
  2497 			S32 bytes = lod_bytes + header_bytes; 
  2500 			// It's possible for the remote asset to have more data than is needed for the local cache
  2501 			// only allocate as much space in the VFS as is needed for the local cache
  2502 			data_size = llmin(data_size, bytes);
  2504 			LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH, LLVFile::WRITE);
  2505 			if (file.getMaxSize() >= bytes || file.setMaxSize(bytes))
  2507 				LLMeshRepository::sCacheBytesWritten += data_size;
  2509 				file.write(data, data_size);
  2511 				// zero out the rest of the file 
  2512 				U8 block[MESH_HEADER_SIZE];
  2513 				memset(block, 0, sizeof(block));
  2515 				while (bytes-file.tell() > sizeof(block))
  2517 					file.write(block, sizeof(block));
  2520 				S32 remaining = bytes-file.tell();
  2521 				if (remaining > 0)
  2523 					file.write(block, remaining);
  2530 LLMeshLODHandler::~LLMeshLODHandler()
  2532 	if (! LLApp::isQuitting())
  2534 		if (! mProcessed)
  2536 			LL_WARNS(LOG_MESH) << "Mesh LOD fetch canceled unexpectedly, retrying." << LL_ENDL;
  2537 			gMeshRepo.mThread->lockAndLoadMeshLOD(mMeshParams, mLOD);
  2539 		LLMeshRepoThread::decActiveLODRequests();
  2543 void LLMeshLODHandler::processFailure(LLCore::HttpStatus status)
  2545 	if (is_retryable(status))
  2547 		LL_WARNS(LOG_MESH) << "Error during mesh header handling.  Reason:  " << status.toString()
  2548 						   << " (" << status.toHex() << ").  Retrying."
  2549 						   << LL_ENDL;
  2551 			LLMutexLock lock(gMeshRepo.mThread->mMutex);
  2553 			gMeshRepo.mThread->loadMeshLOD(mMeshParams, mLOD);
  2556 	else
  2558 		// *TODO:  Mark mesh unavailable
  2559 		LL_WARNS(LOG_MESH) << "Error during mesh LOD handling.  Reason:  " << status.toString()
  2560 						   << " (" << status.toHex() << ").  Not retrying."
  2561 						   << LL_ENDL;
  2565 void LLMeshLODHandler::processData(LLCore::BufferArray * body, U8 * data, S32 data_size)
  2567 	if (gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size))
  2569 		// good fetch from sim, write to VFS for caching
  2570 		LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE);
  2572 		S32 offset = mOffset;
  2573 		S32 size = mRequestedBytes;
  2575 		if (file.getSize() >= offset+size)
  2577 			file.seek(offset);
  2578 			file.write(data, size);
  2579 			LLMeshRepository::sCacheBytesWritten += size;
  2582 	// *TODO:  Mark mesh unavailable on error
  2585 LLMeshSkinInfoHandler::~LLMeshSkinInfoHandler()
  2587 		llassert(mProcessed);
  2590 void LLMeshSkinInfoHandler::processFailure(LLCore::HttpStatus status)
  2592 	if (is_retryable(status))
  2594 		LL_WARNS(LOG_MESH) << "Error during mesh skin info handling.  Reason:  " << status.toString()
  2595 						   << " (" << status.toHex() << ").  Retrying."
  2596 						   << LL_ENDL;
  2598 			LLMutexLock lock(gMeshRepo.mThread->mMutex);
  2600 			gMeshRepo.mThread->loadMeshSkinInfo(mMeshID);
  2603 	else
  2605 		// *TODO:  Mark mesh unavailable on error
  2606 		LL_WARNS(LOG_MESH) << "Error during mesh skin info handling.  Reason:  " << status.toString()
  2607 						   << " (" << status.toHex() << ").  Not retrying."
  2608 						   << LL_ENDL;
  2612 void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * body, U8 * data, S32 data_size)
  2614 	if (gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size))
  2616 		// good fetch from sim, write to VFS for caching
  2617 		LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
  2619 		S32 offset = mOffset;
  2620 		S32 size = mRequestedBytes;
  2622 		if (file.getSize() >= offset+size)
  2624 			LLMeshRepository::sCacheBytesWritten += size;
  2625 			file.seek(offset);
  2626 			file.write(data, size);
  2629 	// *TODO:  Mark mesh unavailable on error
  2632 LLMeshDecompositionHandler::~LLMeshDecompositionHandler()
  2634 		llassert(mProcessed);
  2637 void LLMeshDecompositionHandler::processFailure(LLCore::HttpStatus status)
  2639 	if (is_retryable(status))
  2641 		LL_WARNS(LOG_MESH) << "Error during mesh decomposition handling.  Reason:  " << status.toString()
  2642 						   << " (" << status.toHex() << ").  Retrying."
  2643 						   << LL_ENDL;
  2645 			LLMutexLock lock(gMeshRepo.mThread->mMutex);
  2647 			gMeshRepo.mThread->loadMeshDecomposition(mMeshID);
  2650 	else
  2652 		// *TODO:  Mark mesh unavailable on error
  2653 		LL_WARNS(LOG_MESH) << "Error during mesh decomposition handling.  Reason:  " << status.toString()
  2654 						   << " (" << status.toHex() << ").  Not retrying."
  2655 						   << LL_ENDL;
  2659 void LLMeshDecompositionHandler::processData(LLCore::BufferArray * body, U8 * data, S32 data_size)
  2661 	if (gMeshRepo.mThread->decompositionReceived(mMeshID, data, data_size))
  2663 		// good fetch from sim, write to VFS for caching
  2664 		LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
  2666 		S32 offset = mOffset;
  2667 		S32 size = mRequestedBytes;
  2669 		if (file.getSize() >= offset+size)
  2671 			LLMeshRepository::sCacheBytesWritten += size;
  2672 			file.seek(offset);
  2673 			file.write(data, size);
  2676 	// *TODO:  Mark mesh unavailable on error
  2679 LLMeshPhysicsShapeHandler::~LLMeshPhysicsShapeHandler()
  2681 		llassert(mProcessed);
  2684 void LLMeshPhysicsShapeHandler::processFailure(LLCore::HttpStatus status)
  2686 	if (is_retryable(status))
  2688 		LL_WARNS(LOG_MESH) << "Error during mesh physics shape handling.  Reason:  " << status.toString()
  2689 						   << " (" << status.toHex() << ").  Retrying."
  2690 						   << LL_ENDL;
  2692 			LLMutexLock lock(gMeshRepo.mThread->mMutex);
  2694 			gMeshRepo.mThread->loadMeshPhysicsShape(mMeshID);
  2697 	else
  2699 		// *TODO:  Mark mesh unavailable on error
  2700 		LL_WARNS(LOG_MESH) << "Error during mesh physics shape handling.  Reason:  " << status.toString()
  2701 						   << " (" << status.toHex() << ").  Not retrying."
  2702 						   << LL_ENDL;
  2706 void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * body, U8 * data, S32 data_size)
  2708 	if (gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size))
  2710 		// good fetch from sim, write to VFS for caching
  2711 		LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);
  2713 		S32 offset = mOffset;
  2714 		S32 size = mRequestedBytes;
  2716 		if (file.getSize() >= offset+size)
  2718 			LLMeshRepository::sCacheBytesWritten += size;
  2719 			file.seek(offset);
  2720 			file.write(data, size);
  2723 	// *TODO:  Mark mesh unavailable on error
  2726 LLMeshRepository::LLMeshRepository()
  2727 : mMeshMutex(NULL),
  2728   mMeshThreadCount(0),
  2729   mThread(NULL),
  2730   mGetMeshVersion(2)
  2735 void LLMeshRepository::init()
  2737 	mMeshMutex = new LLMutex(NULL);
  2739 	LLConvexDecomposition::getInstance()->initSystem();
  2741 	mDecompThread = new LLPhysicsDecomp();
  2742 	mDecompThread->start();
  2744 	while (!mDecompThread->mInited)
  2745 	{ //wait for physics decomp thread to init
  2746 		apr_sleep(100);
  2749 	metrics_teleport_started_signal = LLViewerMessage::getInstance()->setTeleportStartedCallback(teleport_started);
  2751 	mThread = new LLMeshRepoThread();
  2752 	mThread->start();
  2756 void LLMeshRepository::shutdown()
  2758 	LL_INFOS(LOG_MESH) << "Shutting down mesh repository." << LL_ENDL;
  2760 	metrics_teleport_started_signal.disconnect();
  2762 	for (U32 i = 0; i < mUploads.size(); ++i)
  2764 		LL_INFOS(LOG_MESH) << "Discard the pending mesh uploads." << LL_ENDL;
  2765 		mUploads[i]->discard() ; //discard the uploading requests.
  2768 	mThread->mSignal->signal();
  2770 	while (!mThread->isStopped())
  2772 		apr_sleep(10);
  2774 	delete mThread;
  2775 	mThread = NULL;
  2777 	for (U32 i = 0; i < mUploads.size(); ++i)
  2779 		LL_INFOS(LOG_MESH) << "Waiting for pending mesh upload " << i << "/" << mUploads.size() << LL_ENDL;
  2780 		while (!mUploads[i]->isStopped())
  2782 			apr_sleep(10);
  2784 		delete mUploads[i];
  2787 	mUploads.clear();
  2789 	delete mMeshMutex;
  2790 	mMeshMutex = NULL;
  2792 	LL_INFOS(LOG_MESH) << "Shutting down decomposition system." << LL_ENDL;
  2794 	if (mDecompThread)
  2796 		mDecompThread->shutdown();		
  2797 		delete mDecompThread;
  2798 		mDecompThread = NULL;
  2801 	LLConvexDecomposition::quitSystem();
  2804 //called in the main thread.
  2805 S32 LLMeshRepository::update()
  2807 	// Conditionally log a mesh metrics event
  2808 	metricsUpdate();
  2810 	if(mUploadWaitList.empty())
  2812 		return 0 ;
  2815 	S32 size = mUploadWaitList.size() ;
  2816 	for (S32 i = 0; i < size; ++i)
  2818 		mUploads.push_back(mUploadWaitList[i]);
  2819 		mUploadWaitList[i]->preStart() ;
  2820 		mUploadWaitList[i]->start() ;
  2822 	mUploadWaitList.clear() ;
  2824 	return size ;
  2827 S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod)
  2829 	// Manage time-to-load metrics for mesh download operations.
  2830 	metricsProgress(1);
  2832 	if (detail < 0 || detail > 4)
  2834 		return detail;
  2838 		LLMutexLock lock(mMeshMutex);
  2839 		//add volume to list of loading meshes
  2840 		mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_params);
  2841 		if (iter != mLoadingMeshes[detail].end())
  2842 		{ //request pending for this mesh, append volume id to list
  2843 			iter->second.insert(vobj->getID());
  2845 		else
  2847 			//first request for this mesh
  2848 			mLoadingMeshes[detail][mesh_params].insert(vobj->getID());
  2849 			mPendingRequests.push_back(LLMeshRepoThread::LODRequest(mesh_params, detail));
  2850 			LLMeshRepository::sLODPending++;
  2854 	//do a quick search to see if we can't display something while we wait for this mesh to load
  2855 	LLVolume* volume = vobj->getVolume();
  2857 	if (volume)
  2859 		LLVolumeParams params = volume->getParams();
  2861 		LLVolumeLODGroup* group = LLPrimitive::getVolumeManager()->getGroup(params);
  2863 		if (group)
  2865 			//first, see if last_lod is available (don't transition down to avoid funny popping a la SH-641)
  2866 			if (last_lod >= 0)
  2868 				LLVolume* lod = group->refLOD(last_lod);
  2869 				if (lod && lod->isMeshAssetLoaded() && lod->getNumVolumeFaces() > 0)
  2871 					group->derefLOD(lod);
  2872 					return last_lod;
  2874 				group->derefLOD(lod);
  2877 			//next, see what the next lowest LOD available might be
  2878 			for (S32 i = detail-1; i >= 0; --i)
  2880 				LLVolume* lod = group->refLOD(i);
  2881 				if (lod && lod->isMeshAssetLoaded() && lod->getNumVolumeFaces() > 0)
  2883 					group->derefLOD(lod);
  2884 					return i;
  2887 				group->derefLOD(lod);
  2890 			//no lower LOD is a available, is a higher lod available?
  2891 			for (S32 i = detail+1; i < 4; ++i)
  2893 				LLVolume* lod = group->refLOD(i);
  2894 				if (lod && lod->isMeshAssetLoaded() && lod->getNumVolumeFaces() > 0)
  2896 					group->derefLOD(lod);
  2897 					return i;
  2900 				group->derefLOD(lod);
  2905 	return detail;
  2908 void LLMeshRepository::notifyLoadedMeshes()
  2909 { //called from main thread
  2910 	if (1 == mGetMeshVersion)
  2912 		// Legacy GetMesh operation with high connection concurrency
  2913 		LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("MeshMaxConcurrentRequests");
  2914 		LLMeshRepoThread::sRequestHighWater = llclamp(2 * S32(LLMeshRepoThread::sMaxConcurrentRequests),
  2915 													  REQUEST_HIGH_WATER_MIN,
  2916 													  REQUEST_HIGH_WATER_MAX);
  2918 	else
  2920 		// GetMesh2 operation with keepalives, etc.
  2921 		// *TODO:  Logic here is replicated from llappcorehttp.cpp, should really
  2922 		// unify this and keep it in one place only.
  2923 		LLMeshRepoThread::sMaxConcurrentRequests = gSavedSettings.getU32("MeshMaxConcurrentRequests") / 4;
  2924 		LLMeshRepoThread::sRequestHighWater = llclamp(5 * S32(LLMeshRepoThread::sMaxConcurrentRequests),
  2925 													  REQUEST_HIGH_WATER_MIN,
  2926 													  REQUEST_HIGH_WATER_MAX);
  2928 	LLMeshRepoThread::sRequestLowWater = llclamp(LLMeshRepoThread::sRequestHighWater / 2,
  2929 												 REQUEST_LOW_WATER_MIN,
  2930 												 REQUEST_LOW_WATER_MAX);
  2932 	//clean up completed upload threads
  2933 	for (std::vector<LLMeshUploadThread*>::iterator iter = mUploads.begin(); iter != mUploads.end(); )
  2935 		LLMeshUploadThread* thread = *iter;
  2937 		if (thread->isStopped() && thread->finished())
  2939 			iter = mUploads.erase(iter);
  2940 			delete thread;
  2942 		else
  2944 			++iter;
  2948 	//update inventory
  2949 	if (!mInventoryQ.empty())
  2951 		LLMutexLock lock(mMeshMutex);
  2952 		while (!mInventoryQ.empty())
  2954 			inventory_data& data = mInventoryQ.front();
  2956 			LLAssetType::EType asset_type = LLAssetType::lookup(data.mPostData["asset_type"].asString());
  2957 			LLInventoryType::EType inventory_type = LLInventoryType::lookup(data.mPostData["inventory_type"].asString());
  2959 			// Handle addition of texture, if any.
  2960 			if ( data.mResponse.has("new_texture_folder_id") )
  2962 				const LLUUID& folder_id = data.mResponse["new_texture_folder_id"].asUUID();
  2964 				if ( folder_id.notNull() )
  2966 					LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE);
  2968 					std::string name;
  2969 					// Check if the server built a different name for the texture folder
  2970 					if ( data.mResponse.has("new_texture_folder_name") )
  2972 						name = data.mResponse["new_texture_folder_name"].asString();
  2974 					else
  2976 						name = data.mPostData["name"].asString();
  2979 					// Add the category to the internal representation
  2980 					LLPointer<LLViewerInventoryCategory> cat = 
  2981 						new LLViewerInventoryCategory(folder_id, parent_id, 
  2982 							LLFolderType::FT_NONE, name, gAgent.getID());
  2983 					cat->setVersion(LLViewerInventoryCategory::VERSION_UNKNOWN);
  2985 					LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1);
  2986 					gInventory.accountForUpdate(update);
  2987 					gInventory.updateCategory(cat);
  2991 			on_new_single_inventory_upload_complete(
  2992 				asset_type,
  2993 				inventory_type,
  2994 				data.mPostData["asset_type"].asString(),
  2995 				data.mPostData["folder_id"].asUUID(),
  2996 				data.mPostData["name"],
  2997 				data.mPostData["description"],
  2998 				data.mResponse,
  2999 				data.mResponse["upload_price"]);
  3000 			//}
  3002 			mInventoryQ.pop();
  3006 	//call completed callbacks on finished decompositions
  3007 	mDecompThread->notifyCompleted();
  3009 	if (!mThread->mWaiting && mPendingRequests.empty())
  3010 	{ //curl thread is churning, wait for it to go idle
  3011 		return;
  3014 	static std::string region_name("never name a region this");
  3016 	if (gAgent.getRegion())
  3017 	{ //update capability url 
  3018 		if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived())
  3020 			region_name = gAgent.getRegion()->getName();
  3021 			mGetMeshCapability = gAgent.getRegion()->getCapability("GetMesh");
  3022 			mGetMesh2Capability = gAgent.getRegion()->getCapability("GetMesh2");
  3023 			mGetMeshVersion = mGetMesh2Capability.empty() ? 1 : 2;
  3024 			LL_DEBUGS(LOG_MESH) << "Retrieving caps for region '" << region_name
  3025 								<< "', GetMesh2:  " << mGetMesh2Capability
  3026 								<< ", GetMesh:  " << mGetMeshCapability
  3027 								<< LL_ENDL;
  3032 		LLMutexLock lock1(mMeshMutex);
  3033 		LLMutexLock lock2(mThread->mMutex);
  3035 		//popup queued error messages from background threads
  3036 		while (!mUploadErrorQ.empty())
  3038 			LLNotificationsUtil::add("MeshUploadError", mUploadErrorQ.front());
  3039 			mUploadErrorQ.pop();
  3042 		S32 active_count = LLMeshRepoThread::sActiveHeaderRequests + LLMeshRepoThread::sActiveLODRequests;
  3043 		if (active_count < LLMeshRepoThread::sRequestLowWater)
  3045 			S32 push_count = LLMeshRepoThread::sRequestHighWater - active_count;
  3047 			if (mPendingRequests.size() > push_count)
  3049 				// More requests than the high-water limit allows so
  3050 				// sort and forward the most important.
  3052 				//calculate "score" for pending requests
  3054 				//create score map
  3055 				std::map<LLUUID, F32> score_map;
  3057 				for (U32 i = 0; i < 4; ++i)
  3059 					for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin();  iter != mLoadingMeshes[i].end(); ++iter)
  3061 						F32 max_score = 0.f;
  3062 						for (std::set<LLUUID>::iterator obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter)
  3064 							LLViewerObject* object = gObjectList.findObject(*obj_iter);
  3066 							if (object)
  3068 								LLDrawable* drawable = object->mDrawable;
  3069 								if (drawable)
  3071 									F32 cur_score = drawable->getRadius()/llmax(drawable->mDistanceWRTCamera, 1.f);
  3072 									max_score = llmax(max_score, cur_score);
  3077 						score_map[iter->first.getSculptID()] = max_score;
  3081 				//set "score" for pending requests
  3082 				for (std::vector<LLMeshRepoThread::LODRequest>::iterator iter = mPendingRequests.begin(); iter != mPendingRequests.end(); ++iter)
  3084 					iter->mScore = score_map[iter->mMeshParams.getSculptID()];
  3087 				//sort by "score"
  3088 				std::partial_sort(mPendingRequests.begin(), mPendingRequests.begin() + push_count,
  3089 								  mPendingRequests.end(), LLMeshRepoThread::CompareScoreGreater());
  3092 			while (!mPendingRequests.empty() && push_count > 0)
  3094 				LLMeshRepoThread::LODRequest& request = mPendingRequests.front();
  3095 				mThread->loadMeshLOD(request.mMeshParams, request.mLOD);
  3096 				mPendingRequests.erase(mPendingRequests.begin());
  3097 				LLMeshRepository::sLODPending--;
  3098 				push_count--;
  3102 		//send skin info requests
  3103 		while (!mPendingSkinRequests.empty())
  3105 			mThread->loadMeshSkinInfo(mPendingSkinRequests.front());
  3106 			mPendingSkinRequests.pop();
  3109 		//send decomposition requests
  3110 		while (!mPendingDecompositionRequests.empty())
  3112 			mThread->loadMeshDecomposition(mPendingDecompositionRequests.front());
  3113 			mPendingDecompositionRequests.pop();
  3116 		//send physics shapes decomposition requests
  3117 		while (!mPendingPhysicsShapeRequests.empty())
  3119 			mThread->loadMeshPhysicsShape(mPendingPhysicsShapeRequests.front());
  3120 			mPendingPhysicsShapeRequests.pop();
  3123 		mThread->notifyLoadedMeshes();
  3126 	mThread->mSignal->signal();
  3129 void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info)
  3131 	mSkinMap[info.mMeshID] = info;
  3133 	skin_load_map::iterator iter = mLoadingSkins.find(info.mMeshID);
  3134 	if (iter != mLoadingSkins.end())
  3136 		for (std::set<LLUUID>::iterator obj_id = iter->second.begin(); obj_id != iter->second.end(); ++obj_id)
  3138 			LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*obj_id);
  3139 			if (vobj)
  3141 				vobj->notifyMeshLoaded();
  3144 		mLoadingSkins.erase(info.mMeshID);
  3148 void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decomp)
  3150 	decomposition_map::iterator iter = mDecompositionMap.find(decomp->mMeshID);
  3151 	if (iter == mDecompositionMap.end())
  3152 	{ //just insert decomp into map
  3153 		mDecompositionMap[decomp->mMeshID] = decomp;
  3154 		mLoadingDecompositions.erase(decomp->mMeshID);
  3156 	else
  3157 	{ //merge decomp with existing entry
  3158 		iter->second->merge(decomp);
  3159 		mLoadingDecompositions.erase(decomp->mMeshID);
  3160 		delete decomp;
  3164 void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume)
  3165 { //called from main thread
  3166 	S32 detail = LLVolumeLODGroup::getVolumeDetailFromScale(volume->getDetail());
  3168 	//get list of objects waiting to be notified this mesh is loaded
  3169 	mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh_params);
  3171 	if (volume && obj_iter != mLoadingMeshes[detail].end())
  3173 		//make sure target volume is still valid
  3174 		if (volume->getNumVolumeFaces() <= 0)
  3176 			LL_WARNS(LOG_MESH) << "Mesh loading returned empty volume.  ID:  " << mesh_params.getSculptID()
  3177 							   << LL_ENDL;
  3180 		{ //update system volume
  3181 			LLVolume* sys_volume = LLPrimitive::getVolumeManager()->refVolume(mesh_params, detail);
  3182 			if (sys_volume)
  3184 				sys_volume->copyVolumeFaces(volume);
  3185 				sys_volume->setMeshAssetLoaded(TRUE);
  3186 				LLPrimitive::getVolumeManager()->unrefVolume(sys_volume);
  3188 			else
  3190 				LL_WARNS(LOG_MESH) << "Couldn't find system volume for mesh " << mesh_params.getSculptID()
  3191 								   << LL_ENDL;
  3195 		//notify waiting LLVOVolume instances that their requested mesh is available
  3196 		for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter)
  3198 			LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);
  3199 			if (vobj)
  3201 				vobj->notifyMeshLoaded();
  3205 		mLoadingMeshes[detail].erase(mesh_params);
  3209 void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod)
  3210 { //called from main thread
  3211 	//get list of objects waiting to be notified this mesh is loaded
  3212 	mesh_load_map::iterator obj_iter = mLoadingMeshes[lod].find(mesh_params);
  3214 	F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod);
  3216 	if (obj_iter != mLoadingMeshes[lod].end())
  3218 		for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter)
  3220 			LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);
  3221 			if (vobj)
  3223 				LLVolume* obj_volume = vobj->getVolume();
  3225 				if (obj_volume && 
  3226 					obj_volume->getDetail() == detail &&
  3227 					obj_volume->getParams() == mesh_params)
  3228 				{ //should force volume to find most appropriate LOD
  3229 					vobj->setVolume(obj_volume->getParams(), lod);
  3234 		mLoadingMeshes[lod].erase(mesh_params);
  3238 S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod)
  3240 	return mThread->getActualMeshLOD(mesh_params, lod);
  3243 const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj)
  3245 	if (mesh_id.notNull())
  3247 		skin_map::iterator iter = mSkinMap.find(mesh_id);
  3248 		if (iter != mSkinMap.end())
  3250 			return &(iter->second);
  3253 		//no skin info known about given mesh, try to fetch it
  3255 			LLMutexLock lock(mMeshMutex);
  3256 			//add volume to list of loading meshes
  3257 			skin_load_map::iterator iter = mLoadingSkins.find(mesh_id);
  3258 			if (iter == mLoadingSkins.end())
  3259 			{ //no request pending for this skin info
  3260 				mPendingSkinRequests.push(mesh_id);
  3262 			mLoadingSkins[mesh_id].insert(requesting_obj->getID());
  3266 	return NULL;
  3269 void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
  3271 	if (mesh_id.notNull())
  3273 		LLModel::Decomposition* decomp = NULL;
  3274 		decomposition_map::iterator iter = mDecompositionMap.find(mesh_id);
  3275 		if (iter != mDecompositionMap.end())
  3277 			decomp = iter->second;
  3280 		//decomposition block hasn't been fetched yet
  3281 		if (!decomp || decomp->mPhysicsShapeMesh.empty())
  3283 			LLMutexLock lock(mMeshMutex);
  3284 			//add volume to list of loading meshes
  3285 			std::set<LLUUID>::iterator iter = mLoadingPhysicsShapes.find(mesh_id);
  3286 			if (iter == mLoadingPhysicsShapes.end())
  3287 			{ //no request pending for this skin info
  3288 				// *FIXME:  Nothing ever deletes entries, can't be right
  3289 				mLoadingPhysicsShapes.insert(mesh_id);
  3290 				mPendingPhysicsShapeRequests.push(mesh_id);
  3297 LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id)
  3299 	LLModel::Decomposition* ret = NULL;
  3301 	if (mesh_id.notNull())
  3303 		decomposition_map::iterator iter = mDecompositionMap.find(mesh_id);
  3304 		if (iter != mDecompositionMap.end())
  3306 			ret = iter->second;
  3309 		//decomposition block hasn't been fetched yet
  3310 		if (!ret || ret->mBaseHullMesh.empty())
  3312 			LLMutexLock lock(mMeshMutex);
  3313 			//add volume to list of loading meshes
  3314 			std::set<LLUUID>::iterator iter = mLoadingDecompositions.find(mesh_id);
  3315 			if (iter == mLoadingDecompositions.end())
  3316 			{ //no request pending for this skin info
  3317 				mLoadingDecompositions.insert(mesh_id);
  3318 				mPendingDecompositionRequests.push(mesh_id);
  3323 	return ret;
  3326 void LLMeshRepository::buildHull(const LLVolumeParams& params, S32 detail)
  3328 	LLVolume* volume = LLPrimitive::sVolumeManager->refVolume(params, detail);
  3330 	if (!volume->mHullPoints)
  3332 		//all default params
  3333 		//execute first stage
  3334 		//set simplify mode to retain
  3335 		//set retain percentage to zero
  3336 		//run second stage
  3339 	LLPrimitive::sVolumeManager->unrefVolume(volume);
  3342 bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id)
  3344 	LLSD mesh = mThread->getMeshHeader(mesh_id);
  3345 	if (mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0))
  3347 		return true;
  3350 	LLModel::Decomposition* decomp = getDecomposition(mesh_id);
  3351 	if (decomp && !decomp->mHull.empty())
  3353 		return true;
  3356 	return false;
  3359 LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id)
  3361 	return mThread->getMeshHeader(mesh_id);
  3364 LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id)
  3366 	static LLSD dummy_ret;
  3367 	if (mesh_id.notNull())
  3369 		LLMutexLock lock(mHeaderMutex);
  3370 		mesh_header_map::iterator iter = mMeshHeader.find(mesh_id);
  3371 		if (iter != mMeshHeader.end())
  3373 			return iter->second;
  3377 	return dummy_ret;
  3381 void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
  3382 								   bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload,
  3383 								   LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer)
  3385 	LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints, upload_url, 
  3386 														do_upload, fee_observer, upload_observer);
  3387 	mUploadWaitList.push_back(thread);
  3390 S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod)
  3392 	if (mThread)
  3394 		LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id);
  3395 		if (iter != mThread->mMeshHeader.end())
  3397 			LLSD& header = iter->second;
  3399 			if (header.has("404"))
  3401 				return -1;
  3404 			S32 size = header[header_lod[lod]]["size"].asInteger();
  3405 			return size;
  3410 	return -1;
  3413 void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation,
  3414 											 LLVector3& result_pos,
  3415 											 LLQuaternion& result_rot,
  3416 											 LLVector3& result_scale)
  3418 	// check for reflection
  3419 	BOOL reflected = (transformation.determinant() < 0);
  3421 	// compute position
  3422 	LLVector3 position = LLVector3(0, 0, 0) * transformation;
  3424 	// compute scale
  3425 	LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position;
  3426 	LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position;
  3427 	LLVector3 z_transformed = LLVector3(0, 0, 1) * transformation - position;
  3428 	F32 x_length = x_transformed.normalize();
  3429 	F32 y_length = y_transformed.normalize();
  3430 	F32 z_length = z_transformed.normalize();
  3431 	LLVector3 scale = LLVector3(x_length, y_length, z_length);
  3433     // adjust for "reflected" geometry
  3434 	LLVector3 x_transformed_reflected = x_transformed;
  3435 	if (reflected)
  3437 		x_transformed_reflected *= -1.0;
  3440 	// compute rotation
  3441 	LLMatrix3 rotation_matrix;
  3442 	rotation_matrix.setRows(x_transformed_reflected, y_transformed, z_transformed);
  3443 	LLQuaternion quat_rotation = rotation_matrix.quaternion();
  3444 	quat_rotation.normalize(); // the rotation_matrix might not have been orthoginal.  make it so here.
  3445 	LLVector3 euler_rotation;
  3446 	quat_rotation.getEulerAngles(&euler_rotation.mV[VX], &euler_rotation.mV[VY], &euler_rotation.mV[VZ]);
  3448 	result_pos = position + mOrigin;
  3449 	result_scale = scale;
  3450 	result_rot = quat_rotation; 
  3453 bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const
  3455 	if (mDiffuseMap != rhs.mDiffuseMap)
  3457 		return mDiffuseMap < rhs.mDiffuseMap;
  3460 	if (mDiffuseMapFilename != rhs.mDiffuseMapFilename)
  3462 		return mDiffuseMapFilename < rhs.mDiffuseMapFilename;
  3465 	if (mDiffuseMapLabel != rhs.mDiffuseMapLabel)
  3467 		return mDiffuseMapLabel < rhs.mDiffuseMapLabel;
  3470 	if (mDiffuseColor != rhs.mDiffuseColor)
  3472 		return mDiffuseColor < rhs.mDiffuseColor;
  3475 	if (mBinding != rhs.mBinding)
  3477 		return mBinding < rhs.mBinding;
  3480 	return mFullbright < rhs.mFullbright;
  3484 void LLMeshRepository::updateInventory(inventory_data data)
  3486 	LLMutexLock lock(mMeshMutex);
  3487 	dump_llsd_to_file(data.mPostData,make_dump_name("update_inventory_post_data_",dump_num));
  3488 	dump_llsd_to_file(data.mResponse,make_dump_name("update_inventory_response_",dump_num));
  3489 	mInventoryQ.push(data);
  3492 void LLMeshRepository::uploadError(LLSD& args)
  3494 	LLMutexLock lock(mMeshMutex);
  3495 	mUploadErrorQ.push(args);
  3498 //static
  3499 F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value)
  3501 	F32 max_distance = 512.f;
  3503 	F32 dlowest = llmin(radius/0.03f, max_distance);
  3504 	F32 dlow = llmin(radius/0.06f, max_distance);
  3505 	F32 dmid = llmin(radius/0.24f, max_distance);
  3507 	F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount");  //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead
  3508 	F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free"
  3510 	F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle");
  3512 	S32 bytes_lowest = header["lowest_lod"]["size"].asInteger();
  3513 	S32 bytes_low = header["low_lod"]["size"].asInteger();
  3514 	S32 bytes_mid = header["medium_lod"]["size"].asInteger();
  3515 	S32 bytes_high = header["high_lod"]["size"].asInteger();
  3517 	if (bytes_high == 0)
  3519 		return 0.f;
  3522 	if (bytes_mid == 0)
  3524 		bytes_mid = bytes_high;
  3527 	if (bytes_low == 0)
  3529 		bytes_low = bytes_mid;
  3532 	if (bytes_lowest == 0)
  3534 		bytes_lowest = bytes_low;
  3537 	F32 triangles_lowest = llmax((F32) bytes_lowest-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
  3538 	F32 triangles_low = llmax((F32) bytes_low-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
  3539 	F32 triangles_mid = llmax((F32) bytes_mid-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
  3540 	F32 triangles_high = llmax((F32) bytes_high-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle;
  3542 	if (bytes)
  3544 		*bytes = 0;
  3545 		*bytes += header["lowest_lod"]["size"].asInteger();
  3546 		*bytes += header["low_lod"]["size"].asInteger();
  3547 		*bytes += header["medium_lod"]["size"].asInteger();
  3548 		*bytes += header["high_lod"]["size"].asInteger();
  3551 	if (bytes_visible)
  3553 		lod = LLMeshRepository::getActualMeshLOD(header, lod);
  3554 		if (lod >= 0 && lod <= 3)
  3556 			*bytes_visible = header[header_lod[lod]]["size"].asInteger();
  3560 	F32 max_area = 102932.f; //area of circle that encompasses region
  3561 	F32 min_area = 1.f;
  3563 	F32 high_area = llmin(F_PI*dmid*dmid, max_area);
  3564 	F32 mid_area = llmin(F_PI*dlow*dlow, max_area);
  3565 	F32 low_area = llmin(F_PI*dlowest*dlowest, max_area);
  3566 	F32 lowest_area = max_area;
  3568 	lowest_area -= low_area;
  3569 	low_area -= mid_area;
  3570 	mid_area -= high_area;
  3572 	high_area = llclamp(high_area, min_area, max_area);
  3573 	mid_area = llclamp(mid_area, min_area, max_area);
  3574 	low_area = llclamp(low_area, min_area, max_area);
  3575 	lowest_area = llclamp(lowest_area, min_area, max_area);
  3577 	F32 total_area = high_area + mid_area + low_area + lowest_area;
  3578 	high_area /= total_area;
  3579 	mid_area /= total_area;
  3580 	low_area /= total_area;
  3581 	lowest_area /= total_area;
  3583 	F32 weighted_avg = triangles_high*high_area +
  3584 					   triangles_mid*mid_area +
  3585 					   triangles_low*low_area +
  3586 					  triangles_lowest*lowest_area;
  3588 	if (unscaled_value)
  3590 		*unscaled_value = weighted_avg;
  3593 	return weighted_avg/gSavedSettings.getU32("MeshTriangleBudget")*15000.f;
  3597 LLPhysicsDecomp::LLPhysicsDecomp()
  3598 : LLThread("Physics Decomp")
  3600 	mInited = false;
  3601 	mQuitting = false;
  3602 	mDone = false;
  3604 	mSignal = new LLCondition(NULL);
  3605 	mMutex = new LLMutex(NULL);
  3608 LLPhysicsDecomp::~LLPhysicsDecomp()
  3610 	shutdown();
  3612 	delete mSignal;
  3613 	mSignal = NULL;
  3614 	delete mMutex;
  3615 	mMutex = NULL;
  3618 void LLPhysicsDecomp::shutdown()
  3620 	if (mSignal)
  3622 		mQuitting = true;
  3623 		mSignal->signal();
  3625 		while (!isStopped())
  3627 			apr_sleep(10);
  3632 void LLPhysicsDecomp::submitRequest(LLPhysicsDecomp::Request* request)
  3634 	LLMutexLock lock(mMutex);
  3635 	mRequestQ.push(request);
  3636 	mSignal->signal();
  3639 //static
  3640 S32 LLPhysicsDecomp::llcdCallback(const char* status, S32 p1, S32 p2)
  3642 	if (gMeshRepo.mDecompThread && gMeshRepo.mDecompThread->mCurRequest.notNull())
  3644 		return gMeshRepo.mDecompThread->mCurRequest->statusCallback(status, p1, p2);
  3647 	return 1;
  3650 void LLPhysicsDecomp::setMeshData(LLCDMeshData& mesh, bool vertex_based)
  3652 	mesh.mVertexBase = mCurRequest->mPositions[0].mV;
  3653 	mesh.mVertexStrideBytes = 12;
  3654 	mesh.mNumVertices = mCurRequest->mPositions.size();
  3656 	if(!vertex_based)
  3658 		mesh.mIndexType = LLCDMeshData::INT_16;
  3659 		mesh.mIndexBase = &(mCurRequest->mIndices[0]);
  3660 		mesh.mIndexStrideBytes = 6;
  3662 		mesh.mNumTriangles = mCurRequest->mIndices.size()/3;
  3665 	if ((vertex_based || mesh.mNumTriangles > 0) && mesh.mNumVertices > 2)
  3667 		LLCDResult ret = LLCD_OK;
  3668 		if (LLConvexDecomposition::getInstance() != NULL)
  3670 			ret  = LLConvexDecomposition::getInstance()->setMeshData(&mesh, vertex_based);
  3673 		if (ret)
  3675 			LL_ERRS(LOG_MESH) << "Convex Decomposition thread valid but could not set mesh data." << LL_ENDL;
  3680 void LLPhysicsDecomp::doDecomposition()
  3682 	LLCDMeshData mesh;
  3683 	S32 stage = mStageID[mCurRequest->mStage];
  3685 	if (LLConvexDecomposition::getInstance() == NULL)
  3687 		// stub library. do nothing.
  3688 		return;
  3691 	//load data intoLLCD
  3692 	if (stage == 0)
  3694 		setMeshData(mesh, false);
  3697 	//build parameter map
  3698 	std::map<std::string, const LLCDParam*> param_map;
  3700 	static const LLCDParam* params = NULL;
  3701 	static S32 param_count = 0;
  3702 	if (!params)
  3704 		param_count = LLConvexDecomposition::getInstance()->getParameters(&params);
  3707 	for (S32 i = 0; i < param_count; ++i)
  3709 		param_map[params[i].mName] = params+i;
  3712 	U32 ret = LLCD_OK;
  3713 	//set parameter values
  3714 	for (decomp_params::iterator iter = mCurRequest->mParams.begin(); iter != mCurRequest->mParams.end(); ++iter)
  3716 		const std::string& name = iter->first;
  3717 		const LLSD& value = iter->second;
  3719 		const LLCDParam* param = param_map[name];
  3721 		if (param == NULL)
  3722 		{ //couldn't find valid parameter
  3723 			continue;
  3727 		if (param->mType == LLCDParam::LLCD_FLOAT)
  3729 			ret = LLConvexDecomposition::getInstance()->setParam(param->mName, (F32) value.asReal());
  3731 		else if (param->mType == LLCDParam::LLCD_INTEGER ||
  3732 			param->mType == LLCDParam::LLCD_ENUM)
  3734 			ret = LLConvexDecomposition::getInstance()->setParam(param->mName, value.asInteger());
  3736 		else if (param->mType == LLCDParam::LLCD_BOOLEAN)
  3738 			ret = LLConvexDecomposition::getInstance()->setParam(param->mName, value.asBoolean());
  3742 	mCurRequest->setStatusMessage("Executing.");
  3744 	if (LLConvexDecomposition::getInstance() != NULL)
  3746 		ret = LLConvexDecomposition::getInstance()->executeStage(stage);
  3749 	if (ret)
  3751 		LL_WARNS(LOG_MESH) << "Convex Decomposition thread valid but could not execute stage " << stage << "."
  3752 						   << LL_ENDL;
  3753 		LLMutexLock lock(mMutex);
  3755 		mCurRequest->mHull.clear();
  3756 		mCurRequest->mHullMesh.clear();
  3758 		mCurRequest->setStatusMessage("FAIL");
  3760 		completeCurrent();
  3762 	else
  3764 		mCurRequest->setStatusMessage("Reading results");
  3766 		S32 num_hulls =0;
  3767 		if (LLConvexDecomposition::getInstance() != NULL)
  3769 			num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(stage);
  3773 			LLMutexLock lock(mMutex);
  3774 			mCurRequest->mHull.clear();
  3775 			mCurRequest->mHull.resize(num_hulls);
  3777 			mCurRequest->mHullMesh.clear();
  3778 			mCurRequest->mHullMesh.resize(num_hulls);
  3781 		for (S32 i = 0; i < num_hulls; ++i)
  3783 			std::vector<LLVector3> p;
  3784 			LLCDHull hull;
  3785 			// if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code
  3786 			LLConvexDecomposition::getInstance()->getHullFromStage(stage, i, &hull);
  3788 			const F32* v = hull.mVertexBase;
  3790 			for (S32 j = 0; j < hull.mNumVertices; ++j)
  3792 				LLVector3 vert(v[0], v[1], v[2]); 
  3793 				p.push_back(vert);
  3794 				v = (F32*) (((U8*) v) + hull.mVertexStrideBytes);
  3797 			LLCDMeshData mesh;
  3798 			// if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code
  3799 			LLConvexDecomposition::getInstance()->getMeshFromStage(stage, i, &mesh);
  3801 			get_vertex_buffer_from_mesh(mesh, mCurRequest->mHullMesh[i]);
  3804 				LLMutexLock lock(mMutex);
  3805 				mCurRequest->mHull[i] = p;
  3810 			LLMutexLock lock(mMutex);
  3811 			mCurRequest->setStatusMessage("FAIL");
  3812 			completeCurrent();						
  3817 void LLPhysicsDecomp::completeCurrent()
  3819 	LLMutexLock lock(mMutex);
  3820 	mCompletedQ.push(mCurRequest);
  3821 	mCurRequest = NULL;
  3824 void LLPhysicsDecomp::notifyCompleted()
  3826 	if (!mCompletedQ.empty())
  3828 		LLMutexLock lock(mMutex);
  3829 		while (!mCompletedQ.empty())
  3831 			Request* req = mCompletedQ.front();
  3832 			req->completed();
  3833 			mCompletedQ.pop();
  3839 void make_box(LLPhysicsDecomp::Request * request)
  3841 	LLVector3 min,max;
  3842 	min = request->mPositions[0];
  3843 	max = min;
  3845 	for (U32 i = 0; i < request->mPositions.size(); ++i)
  3847 		update_min_max(min, max, request->mPositions[i]);
  3850 	request->mHull.clear();
  3852 	LLModel::hull box;
  3853 	box.push_back(LLVector3(min[0],min[1],min[2]));
  3854 	box.push_back(LLVector3(max[0],min[1],min[2]));
  3855 	box.push_back(LLVector3(min[0],max[1],min[2]));
  3856 	box.push_back(LLVector3(max[0],max[1],min[2]));
  3857 	box.push_back(LLVector3(min[0],min[1],max[2]));
  3858 	box.push_back(LLVector3(max[0],min[1],max[2]));
  3859 	box.push_back(LLVector3(min[0],max[1],max[2]));
  3860 	box.push_back(LLVector3(max[0],max[1],max[2]));
  3862 	request->mHull.push_back(box);
  3866 void LLPhysicsDecomp::doDecompositionSingleHull()
  3868 	LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance();
  3870 	if (decomp == NULL)
  3872 		//stub. do nothing.
  3873 		return;
  3876 	LLCDMeshData mesh;	
  3878 	setMeshData(mesh, true);
  3880 	LLCDResult ret = decomp->buildSingleHull() ;
  3881 	if (ret)
  3883 		LL_WARNS(LOG_MESH) << "Could not execute decomposition stage when attempting to create single hull." << LL_ENDL;
  3884 		make_box(mCurRequest);
  3886 	else
  3889 			LLMutexLock lock(mMutex);
  3890 			mCurRequest->mHull.clear();
  3891 			mCurRequest->mHull.resize(1);
  3892 			mCurRequest->mHullMesh.clear();
  3895 		std::vector<LLVector3> p;
  3896 		LLCDHull hull;
  3898 		// if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code
  3899 		decomp->getSingleHull(&hull);
  3901 		const F32* v = hull.mVertexBase;
  3903 		for (S32 j = 0; j < hull.mNumVertices; ++j)
  3905 			LLVector3 vert(v[0], v[1], v[2]); 
  3906 			p.push_back(vert);
  3907 			v = (F32*) (((U8*) v) + hull.mVertexStrideBytes);
  3911 			LLMutexLock lock(mMutex);
  3912 			mCurRequest->mHull[0] = p;
  3917 		completeCurrent();
  3923 void LLPhysicsDecomp::run()
  3925 	LLConvexDecomposition* decomp = LLConvexDecomposition::getInstance();
  3926 	if (decomp == NULL)
  3928 		// stub library. Set init to true so the main thread
  3929 		// doesn't wait for this to finish.
  3930 		mInited = true;
  3931 		return;
  3934 	decomp->initThread();
  3935 	mInited = true;
  3937 	static const LLCDStageData* stages = NULL;
  3938 	static S32 num_stages = 0;
  3940 	if (!stages)
  3942 		num_stages = decomp->getStages(&stages);
  3945 	for (S32 i = 0; i < num_stages; i++)
  3947 		mStageID[stages[i].mName] = i;
  3950 	while (!mQuitting)
  3952 		mSignal->wait();
  3953 		while (!mQuitting && !mRequestQ.empty())
  3956 				LLMutexLock lock(mMutex);
  3957 				mCurRequest = mRequestQ.front();
  3958 				mRequestQ.pop();
  3961 			S32& id = *(mCurRequest->mDecompID);
  3962 			if (id == -1)
  3964 				decomp->genDecomposition(id);
  3966 			decomp->bindDecomposition(id);
  3968 			if (mCurRequest->mStage == "single_hull")
  3970 				doDecompositionSingleHull();
  3972 			else
  3974 				doDecomposition();
  3979 	decomp->quitThread();
  3981 	if (mSignal->isLocked())
  3982 	{ //let go of mSignal's associated mutex
  3983 		mSignal->unlock();
  3986 	mDone = true;
  3989 void LLPhysicsDecomp::Request::assignData(LLModel* mdl) 
  3991 	if (!mdl)
  3993 		return ;
  3996 	U16 index_offset = 0;
  3997 	U16 tri[3] ;
  3999 	mPositions.clear();
  4000 	mIndices.clear();
  4001 	mBBox[1] = LLVector3(F32_MIN, F32_MIN, F32_MIN) ;
  4002 	mBBox[0] = LLVector3(F32_MAX, F32_MAX, F32_MAX) ;
  4004 	//queue up vertex positions and indices
  4005 	for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
  4007 		const LLVolumeFace& face = mdl->getVolumeFace(i);
  4008 		if (mPositions.size() + face.mNumVertices > 65535)
  4010 			continue;
  4013 		for (U32 j = 0; j < face.mNumVertices; ++j)
  4015 			mPositions.push_back(LLVector3(face.mPositions[j].getF32ptr()));
  4016 			for(U32 k = 0 ; k < 3 ; k++)
  4018 				mBBox[0].mV[k] = llmin(mBBox[0].mV[k], mPositions[j].mV[k]) ;
  4019 				mBBox[1].mV[k] = llmax(mBBox[1].mV[k], mPositions[j].mV[k]) ;
  4023 		updateTriangleAreaThreshold() ;
  4025 		for (U32 j = 0; j+2 < face.mNumIndices; j += 3)
  4027 			tri[0] = face.mIndices[j] + index_offset ;
  4028 			tri[1] = face.mIndices[j + 1] + index_offset ;
  4029 			tri[2] = face.mIndices[j + 2] + index_offset ;
  4031 			if(isValidTriangle(tri[0], tri[1], tri[2]))
  4033 				mIndices.push_back(tri[0]);
  4034 				mIndices.push_back(tri[1]);
  4035 				mIndices.push_back(tri[2]);
  4039 		index_offset += face.mNumVertices;
  4042 	return ;
  4045 void LLPhysicsDecomp::Request::updateTriangleAreaThreshold() 
  4047 	F32 range = mBBox[1].mV[0] - mBBox[0].mV[0] ;
  4048 	range = llmin(range, mBBox[1].mV[1] - mBBox[0].mV[1]) ;
  4049 	range = llmin(range, mBBox[1].mV[2] - mBBox[0].mV[2]) ;
  4051 	mTriangleAreaThreshold = llmin(0.0002f, range * 0.000002f) ;
  4054 //check if the triangle area is large enough to qualify for a valid triangle
  4055 bool LLPhysicsDecomp::Request::isValidTriangle(U16 idx1, U16 idx2, U16 idx3) 
  4057 	LLVector3 a = mPositions[idx2] - mPositions[idx1] ;
  4058 	LLVector3 b = mPositions[idx3] - mPositions[idx1] ;
  4059 	F32 c = a * b ;
  4061 	return ((a*a) * (b*b) - c * c) > mTriangleAreaThreshold ;
  4064 void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg)
  4066 	mStatusMessage = msg;
  4069 LLModelInstance::LLModelInstance(LLSD& data)
  4071 	mLocalMeshID = data["mesh_id"].asInteger();
  4072 	mLabel = data["label"].asString();
  4073 	mTransform.setValue(data["transform"]);
  4075 	for (U32 i = 0; i < data["material"].size(); ++i)
  4077 		LLImportMaterial mat(data["material"][i]);
  4078 		mMaterial[mat.mBinding] = mat;
  4083 LLSD LLModelInstance::asLLSD()
  4085 	LLSD ret;
  4087 	ret["mesh_id"] = mModel->mLocalID;
  4088 	ret["label"] = mLabel;
  4089 	ret["transform"] = mTransform.getValue();
  4091 	U32 i = 0;
  4092 	for (std::map<std::string, LLImportMaterial>::iterator iter = mMaterial.begin(); iter != mMaterial.end(); ++iter)
  4094 		ret["material"][i++] = iter->second.asLLSD();
  4097 	return ret;
  4100 LLImportMaterial::LLImportMaterial(LLSD& data)
  4102 	mDiffuseMapFilename = data["diffuse"]["filename"].asString();
  4103 	mDiffuseMapLabel = data["diffuse"]["label"].asString();
  4104 	mDiffuseColor.setValue(data["diffuse"]["color"]);
  4105 	mFullbright = data["fullbright"].asBoolean();
  4106 	mBinding = data["binding"].asString();
  4110 LLSD LLImportMaterial::asLLSD()
  4112 	LLSD ret;
  4114 	ret["diffuse"]["filename"] = mDiffuseMapFilename;
  4115 	ret["diffuse"]["label"] = mDiffuseMapLabel;
  4116 	ret["diffuse"]["color"] = mDiffuseColor.getValue();
  4117 	ret["fullbright"] = mFullbright;
  4118 	ret["binding"] = mBinding;
  4120 	return ret;
  4123 void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp)
  4125 	decomp.mMesh.resize(decomp.mHull.size());
  4127 	for (U32 i = 0; i < decomp.mHull.size(); ++i)
  4129 		LLCDHull hull;
  4130 		hull.mNumVertices = decomp.mHull[i].size();
  4131 		hull.mVertexBase = decomp.mHull[i][0].mV;
  4132 		hull.mVertexStrideBytes = 12;
  4134 		LLCDMeshData mesh;
  4135 		LLCDResult res = LLCD_OK;
  4136 		if (LLConvexDecomposition::getInstance() != NULL)
  4138 			res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh);
  4140 		if (res == LLCD_OK)
  4142 			get_vertex_buffer_from_mesh(mesh, decomp.mMesh[i]);
  4146 	if (!decomp.mBaseHull.empty() && decomp.mBaseHullMesh.empty())
  4147 	{ //get mesh for base hull
  4148 		LLCDHull hull;
  4149 		hull.mNumVertices = decomp.mBaseHull.size();
  4150 		hull.mVertexBase = decomp.mBaseHull[0].mV;
  4151 		hull.mVertexStrideBytes = 12;
  4153 		LLCDMeshData mesh;
  4154 		LLCDResult res = LLCD_OK;
  4155 		if (LLConvexDecomposition::getInstance() != NULL)
  4157 			res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh);
  4159 		if (res == LLCD_OK)
  4161 			get_vertex_buffer_from_mesh(mesh, decomp.mBaseHullMesh);
  4167 bool LLMeshRepository::meshUploadEnabled()
  4169 	LLViewerRegion *region = gAgent.getRegion();
  4170 	if(gSavedSettings.getBOOL("MeshEnabled") &&
  4171 	   region)
  4173 		return region->meshUploadEnabled();
  4175 	return false;
  4178 bool LLMeshRepository::meshRezEnabled()
  4180 	LLViewerRegion *region = gAgent.getRegion();
  4181 	if(gSavedSettings.getBOOL("MeshEnabled") && 
  4182 	   region)
  4184 		return region->meshRezEnabled();
  4186 	return false;
  4189 // Threading:  main thread only
  4190 // static
  4191 void LLMeshRepository::metricsStart()
  4193 	++metrics_teleport_start_count;
  4194 	sQuiescentTimer.start(0);
  4197 // Threading:  main thread only
  4198 // static
  4199 void LLMeshRepository::metricsStop()
  4201 	sQuiescentTimer.stop(0);
  4204 // Threading:  main thread only
  4205 // static
  4206 void LLMeshRepository::metricsProgress(unsigned int this_count)
  4208 	static bool first_start(true);
  4210 	if (first_start)
  4212 		metricsStart();
  4213 		first_start = false;
  4215 	sQuiescentTimer.ringBell(0, this_count);
  4218 // Threading:  main thread only
  4219 // static
  4220 void LLMeshRepository::metricsUpdate()
  4222 	F64 started, stopped;
  4223 	U64 total_count(U64L(0)), user_cpu(U64L(0)), sys_cpu(U64L(0));
  4225 	if (sQuiescentTimer.isExpired(0, started, stopped, total_count, user_cpu, sys_cpu))
  4227 		LLSD metrics;
  4229 		metrics["reason"] = "Mesh Download Quiescent";
  4230 		metrics["scope"] = "Login";
  4231 		metrics["start"] = started;
  4232 		metrics["stop"] = stopped;
  4233 		metrics["fetches"] = LLSD::Integer(total_count);
  4234 		metrics["teleports"] = LLSD::Integer(metrics_teleport_start_count);
  4235 		metrics["user_cpu"] = double(user_cpu) / 1.0e6;
  4236 		metrics["sys_cpu"] = double(sys_cpu) / 1.0e6;
  4237 		LL_INFOS(LOG_MESH) << "EventMarker " << metrics << LL_ENDL;
  4241 // Threading:  main thread only
  4242 // static
  4243 void teleport_started()
  4245 	LLMeshRepository::metricsStart();
  4248 // *TODO:  This comes from an edit in viewer-cat.  Unify this once that's
  4249 // available everywhere.
  4250 bool is_retryable(LLCore::HttpStatus status)
  4252 	static const LLCore::HttpStatus cant_connect(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT);
  4253 	static const LLCore::HttpStatus cant_res_proxy(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_RESOLVE_PROXY);
  4254 	static const LLCore::HttpStatus cant_res_host(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_RESOLVE_HOST);
  4255 	static const LLCore::HttpStatus send_error(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SEND_ERROR);
  4256 	static const LLCore::HttpStatus recv_error(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_RECV_ERROR);
  4257 	static const LLCore::HttpStatus upload_failed(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_UPLOAD_FAILED);
  4258 	static const LLCore::HttpStatus op_timedout(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT);
  4259 	static const LLCore::HttpStatus post_error(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_HTTP_POST_ERROR);
  4260 	static const LLCore::HttpStatus partial_file(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_PARTIAL_FILE);
  4261 	static const LLCore::HttpStatus inv_cont_range(LLCore::HttpStatus::LLCORE, LLCore::HE_INV_CONTENT_RANGE_HDR);
  4263 	return ((! status) &&
  4264 			((status.isHttpStatus() && status.mType >= 499 && status.mType <= 599) ||		// Include special 499 in retryables
  4265 			 status == cant_connect ||			// Connection reset/endpoint problems
  4266 			 status == cant_res_proxy ||		// DNS problems
  4267 			 status == cant_res_host ||			// DNS problems
  4268 			 status == send_error ||			// General socket problems
  4269 			 status == recv_error ||			// General socket problems
  4270 			 status == upload_failed ||			// Transport problem
  4271 			 status == op_timedout ||			// Timer expired
  4272 			 status == post_error ||			// Transport problem
  4273 			 status == partial_file ||			// Data inconsistency in response
  4274 			 status == inv_cont_range));		// Short data read disagrees with content-range

mercurial