aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDr Scofield2009-06-25 07:42:06 +0000
committerDr Scofield2009-06-25 07:42:06 +0000
commitafd5f76648740b80fdfe6cfdfca82e3def5baf03 (patch)
tree1adbd4b99be8e3c1fc0f38dcb4de08283f6d0f9d
parent- fixes a "collection out of sync" exception in the ODE physics (diff)
downloadopensim-SC-afd5f76648740b80fdfe6cfdfca82e3def5baf03.zip
opensim-SC-afd5f76648740b80fdfe6cfdfca82e3def5baf03.tar.gz
opensim-SC-afd5f76648740b80fdfe6cfdfca82e3def5baf03.tar.bz2
opensim-SC-afd5f76648740b80fdfe6cfdfca82e3def5baf03.tar.xz
From: Alan Webb <alan_webb@us.ibm.com>
This change moves texture send processing out of the main packet processing loop and moves it to a timer based processing cycle. Texture packets are sent to the client consistently over time. The timer is discontinued whenever there are no textures to transmit. The behavior of the texture sending mechanism is controlled by three variables in the LLCLient section of the config file: [1] TextureRequestRate (mS) determines how many times per second texture send processing will occur. The default is 100mS. [2] TextureSendLimit determines how many different textures will be considered on each cycle. Textures are selected by priority. The old mechanism specified a value of 10 for this parameter and this is the default [3] TextureDataLimit determines how many packets will be sent for each of the selected textures. The old mechanism specified a value of 5, so this is the default. So the net effect is that TextureSendLimit*TextureDataLimit packets will be sent every TextureRequestRate mS. Once we have gotten a reasonable feeling for how these parameters affect overall processing, it would be nice to autonmically manage these values using information about the current status of the region and network. Note that this also resolves the pathologcal problem that previously existed which was that a seated avatar generated very few in-bound packets (theoretically) and would therefore be the least able to retrieve the images being displayed by a projector script.
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs8
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs152
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs81
-rw-r--r--bin/OpenSim.ini.example19
4 files changed, 185 insertions, 75 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
index 5ba5df1..6cffd70 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs
@@ -260,7 +260,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
260 return false; 260 return false;
261 } 261 }
262 } 262 }
263 public bool SendPackets(LLClientView client) 263 public bool SendPackets(LLClientView client, int maxpack)
264 { 264 {
265 265
266 if (!m_completedSendAtCurrentDiscardLevel) 266 if (!m_completedSendAtCurrentDiscardLevel)
@@ -284,7 +284,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
284 } 284 }
285 285
286 int count = 0; 286 int count = 0;
287 while (SendMore && count < 5 && m_packetNumber <= m_stopPacket) 287 while (SendMore && count < maxpack && m_packetNumber <= m_stopPacket)
288 { 288 {
289 count++; 289 count++;
290 SendMore = SendPacket(client); 290 SendMore = SendPacket(client);
@@ -391,6 +391,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
391 } 391 }
392 } 392 }
393 } 393 }
394 else
395 {
396 m_packetNumber = m_stopPacket;
397 }
394 } 398 }
395 } 399 }
396 } 400 }
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index cda4d49..2884268 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -80,6 +80,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
80 private List<ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates = 80 private List<ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates =
81 new List<ObjectUpdatePacket.ObjectDataBlock>(); 81 new List<ObjectUpdatePacket.ObjectDataBlock>();
82 82
83 private Timer m_textureRequestTimer;
84
83 private bool m_clientBlocked; 85 private bool m_clientBlocked;
84 86
85 private int m_probesWithNoIngressPackets; 87 private int m_probesWithNoIngressPackets;
@@ -140,6 +142,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
140 protected int m_primTerseUpdateRate = 10; 142 protected int m_primTerseUpdateRate = 10;
141 protected int m_primFullUpdateRate = 14; 143 protected int m_primFullUpdateRate = 14;
142 144
145 protected int m_textureRequestRate = 100;
146 protected int m_textureSendLimit = 10;
147 protected int m_textureDataLimit = 5;
148
143 protected int m_packetMTU = 1400; 149 protected int m_packetMTU = 1400;
144 150
145 protected IAssetService m_assetService; 151 protected IAssetService m_assetService;
@@ -344,6 +350,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
344 350
345 private readonly IGroupsModule m_GroupsModule; 351 private readonly IGroupsModule m_GroupsModule;
346 352
353 private AgentUpdateArgs lastarg = null;
354
347 //private TerrainUnacked handlerUnackedTerrain = null; 355 //private TerrainUnacked handlerUnackedTerrain = null;
348 356
349 //** 357 //**
@@ -544,6 +552,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
544 m_primFullUpdateRate = clientConfig.GetInt("FullUpdateRate", 552 m_primFullUpdateRate = clientConfig.GetInt("FullUpdateRate",
545 m_primFullUpdateRate); 553 m_primFullUpdateRate);
546 554
555 m_textureRequestRate = clientConfig.GetInt("TextureRequestRate",
556 m_textureRequestRate);
557
558 m_textureSendLimit = clientConfig.GetInt("TextureSendLimit",
559 m_textureSendLimit);
560
561 m_textureDataLimit = clientConfig.GetInt("TextureDataLimit",
562 m_textureDataLimit);
563
547 m_packetMTU = clientConfig.GetInt("PacketMTU", 1400); 564 m_packetMTU = clientConfig.GetInt("PacketMTU", 1400);
548 } 565 }
549 } 566 }
@@ -577,6 +594,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
577 m_avatarTerseUpdateTimer.Stop(); 594 m_avatarTerseUpdateTimer.Stop();
578 m_primTerseUpdateTimer.Stop(); 595 m_primTerseUpdateTimer.Stop();
579 m_primFullUpdateTimer.Stop(); 596 m_primFullUpdateTimer.Stop();
597 m_textureRequestTimer.Stop();
580 598
581 // This is just to give the client a reasonable chance of 599 // This is just to give the client a reasonable chance of
582 // flushing out all it's packets. There should probably 600 // flushing out all it's packets. There should probably
@@ -660,6 +678,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
660 m_avatarTerseUpdateTimer.Stop(); 678 m_avatarTerseUpdateTimer.Stop();
661 m_primTerseUpdateTimer.Stop(); 679 m_primTerseUpdateTimer.Stop();
662 m_primFullUpdateTimer.Stop(); 680 m_primFullUpdateTimer.Stop();
681 m_textureRequestTimer.Stop();
663 } 682 }
664 683
665 public void Restart() 684 public void Restart()
@@ -682,6 +701,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
682 m_primFullUpdateTimer = new Timer(m_primFullUpdateRate); 701 m_primFullUpdateTimer = new Timer(m_primFullUpdateRate);
683 m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates); 702 m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates);
684 m_primFullUpdateTimer.AutoReset = false; 703 m_primFullUpdateTimer.AutoReset = false;
704
705 m_textureRequestTimer = new Timer(m_textureRequestRate);
706 m_textureRequestTimer.Elapsed += new ElapsedEventHandler(ProcessTextureRequests);
707 m_textureRequestTimer.AutoReset = false;
708
685 } 709 }
686 710
687 public void Terminate() 711 public void Terminate()
@@ -914,6 +938,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
914 m_primFullUpdateTimer = new Timer(m_primFullUpdateRate); 938 m_primFullUpdateTimer = new Timer(m_primFullUpdateRate);
915 m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates); 939 m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates);
916 m_primFullUpdateTimer.AutoReset = false; 940 m_primFullUpdateTimer.AutoReset = false;
941
942 m_textureRequestTimer = new Timer(m_textureRequestRate);
943 m_textureRequestTimer.Elapsed += new ElapsedEventHandler(ProcessTextureRequests);
944 m_textureRequestTimer.AutoReset = false;
945
917 m_scene.AddNewClient(this); 946 m_scene.AddNewClient(this);
918 947
919 RefreshGroupMembership(); 948 RefreshGroupMembership();
@@ -985,6 +1014,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
985 } 1014 }
986 } 1015 }
987 1016
1017 protected virtual void TextureRequestHandler()
1018 {
1019 m_log.DebugFormat("[TRH] Thread started");
1020 while (m_imageManager != null)
1021 {
1022 try
1023 {
1024 while (m_imageManager != null)
1025 {
1026 }
1027 }
1028 catch (Exception e)
1029 {
1030 m_log.WarnFormat("[TRH] Exception in handler loop: {0}", e.Message);
1031 m_log.Debug(e);
1032 }
1033 }
1034 m_log.DebugFormat("[TRH] Thread terminated");
1035 }
1036
988 # endregion 1037 # endregion
989 1038
990 // Previously ClientView.API partial class 1039 // Previously ClientView.API partial class
@@ -3032,6 +3081,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3032 } 3081 }
3033 } 3082 }
3034 3083
3084 // Unlike the other timers, this one is only started after
3085 // the first request is seen.
3086
3087 void ProcessTextureRequests(object sender, ElapsedEventArgs e)
3088 {
3089 if (m_imageManager != null)
3090 {
3091 if (m_imageManager.ProcessImageQueue(m_textureSendLimit,
3092 m_textureDataLimit))
3093 {
3094 m_textureRequestTimer.Start();
3095 }
3096 }
3097 }
3098
3035 void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e) 3099 void ProcessPrimFullUpdates(object sender, ElapsedEventArgs e)
3036 { 3100 {
3037 lock (m_primFullUpdates) 3101 lock (m_primFullUpdates)
@@ -3237,7 +3301,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3237 ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec) 3301 ushort numParts, UUID ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec)
3238 { 3302 {
3239 ImageDataPacket im = new ImageDataPacket(); 3303 ImageDataPacket im = new ImageDataPacket();
3240 im.Header.Reliable = true; 3304 im.Header.Reliable = false;
3241 im.ImageID.Packets = numParts; 3305 im.ImageID.Packets = numParts;
3242 im.ImageID.ID = ImageUUID; 3306 im.ImageID.ID = ImageUUID;
3243 3307
@@ -3253,7 +3317,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3253 public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData) 3317 public void SendImageNextPart(ushort partNumber, UUID imageUuid, byte[] imageData)
3254 { 3318 {
3255 ImagePacketPacket im = new ImagePacketPacket(); 3319 ImagePacketPacket im = new ImagePacketPacket();
3256 im.Header.Reliable = true; 3320 im.Header.Reliable = false;
3257 im.ImageID.Packet = partNumber; 3321 im.ImageID.Packet = partNumber;
3258 im.ImageID.ID = imageUuid; 3322 im.ImageID.ID = imageUuid;
3259 im.ImageData.Data = imageData; 3323 im.ImageData.Data = imageData;
@@ -4727,14 +4791,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4727 /// <param name="Pack">OpenMetaverse.packet</param> 4791 /// <param name="Pack">OpenMetaverse.packet</param>
4728 public void ProcessInPacket(Packet Pack) 4792 public void ProcessInPacket(Packet Pack)
4729 { 4793 {
4730 // check if we've got a local packet handler for this packet.type. See RegisterLocalPacketHandlers() 4794
4731 if (ProcessPacketMethod(Pack)) 4795 if (ProcessPacketMethod(Pack))
4732 { 4796 {
4733 //there is a handler registered that handled this packet type
4734
4735 // in the end, we dereference this, so we have to check if it's null
4736 if (m_imageManager != null)
4737 m_imageManager.ProcessImageQueue(5);
4738 return; 4797 return;
4739 } 4798 }
4740 4799
@@ -5303,6 +5362,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5303 case PacketType.AgentUpdate: 5362 case PacketType.AgentUpdate:
5304 if (OnAgentUpdate != null) 5363 if (OnAgentUpdate != null)
5305 { 5364 {
5365 bool update = false;
5306 AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack; 5366 AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack;
5307 5367
5308 #region Packet Session and User Check 5368 #region Packet Session and User Check
@@ -5315,26 +5375,58 @@ namespace OpenSim.Region.ClientStack.LindenUDP
5315 #endregion 5375 #endregion
5316 5376
5317 AgentUpdatePacket.AgentDataBlock x = agenUpdate.AgentData; 5377 AgentUpdatePacket.AgentDataBlock x = agenUpdate.AgentData;
5318 AgentUpdateArgs arg = new AgentUpdateArgs();
5319 arg.AgentID = x.AgentID;
5320 arg.BodyRotation = x.BodyRotation;
5321 arg.CameraAtAxis = x.CameraAtAxis;
5322 arg.CameraCenter = x.CameraCenter;
5323 arg.CameraLeftAxis = x.CameraLeftAxis;
5324 arg.CameraUpAxis = x.CameraUpAxis;
5325 arg.ControlFlags = x.ControlFlags;
5326 arg.Far = x.Far;
5327 arg.Flags = x.Flags;
5328 arg.HeadRotation = x.HeadRotation;
5329 arg.SessionID = x.SessionID;
5330 arg.State = x.State;
5331 5378
5332 handlerAgentUpdate = OnAgentUpdate; 5379 // We can only check when we have something to check
5333 if (handlerAgentUpdate != null) 5380 // against.
5334 OnAgentUpdate(this, arg); 5381
5382 if (lastarg != null)
5383 {
5384 update =
5385 (
5386 (x.BodyRotation != lastarg.BodyRotation) ||
5387 (x.CameraAtAxis != lastarg.CameraAtAxis) ||
5388 (x.CameraCenter != lastarg.CameraCenter) ||
5389 (x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
5390 (x.CameraUpAxis != lastarg.CameraUpAxis) ||
5391 (x.ControlFlags != lastarg.ControlFlags) ||
5392 (x.Far != lastarg.Far) ||
5393 (x.Flags != lastarg.Flags) ||
5394 (x.State != lastarg.State) ||
5395 (x.HeadRotation != lastarg.HeadRotation) ||
5396 (x.SessionID != lastarg.SessionID) ||
5397 (x.AgentID != lastarg.AgentID)
5398 );
5399 }
5400 else
5401 update = true;
5402
5403 // These should be ordered from most-likely to
5404 // least likely to change. I've made an initial
5405 // guess at that.
5406
5407 if (update)
5408 {
5409 AgentUpdateArgs arg = new AgentUpdateArgs();
5410 arg.AgentID = x.AgentID;
5411 arg.BodyRotation = x.BodyRotation;
5412 arg.CameraAtAxis = x.CameraAtAxis;
5413 arg.CameraCenter = x.CameraCenter;
5414 arg.CameraLeftAxis = x.CameraLeftAxis;
5415 arg.CameraUpAxis = x.CameraUpAxis;
5416 arg.ControlFlags = x.ControlFlags;
5417 arg.Far = x.Far;
5418 arg.Flags = x.Flags;
5419 arg.HeadRotation = x.HeadRotation;
5420 arg.SessionID = x.SessionID;
5421 arg.State = x.State;
5422 handlerAgentUpdate = OnAgentUpdate;
5423 lastarg = arg; // save this set of arguments for nexttime
5424 if (handlerAgentUpdate != null)
5425 OnAgentUpdate(this, arg);
5426
5427 handlerAgentUpdate = null;
5428 }
5335 5429
5336 handlerAgentUpdate = null;
5337 //agenUpdate.AgentData.ControlFlags, agenUpdate.AgentData.BodyRotationa);
5338 } 5430 }
5339 break; 5431 break;
5340 5432
@@ -6392,10 +6484,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
6392 6484
6393 // in the end, we null this, so we have to check if it's null 6485 // in the end, we null this, so we have to check if it's null
6394 if (m_imageManager != null) 6486 if (m_imageManager != null)
6487 {
6395 m_imageManager.EnqueueReq(args); 6488 m_imageManager.EnqueueReq(args);
6489 m_textureRequestTimer.Start();
6490 }
6396 } 6491 }
6397 } 6492 }
6398 break; 6493 break;
6494
6399 case PacketType.TransferRequest: 6495 case PacketType.TransferRequest:
6400 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request"); 6496 //m_log.Debug("ClientView.ProcessPackets.cs:ProcessInPacket() - Got transfer request");
6401 6497
@@ -9502,10 +9598,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9502 #endregion 9598 #endregion
9503 } 9599 }
9504 9600
9505 // in the end, we dereference this, so we have to check if it's null
9506 if (m_imageManager != null)
9507 m_imageManager.ProcessImageQueue(10);
9508 PacketPool.Instance.ReturnPacket(Pack); 9601 PacketPool.Instance.ReturnPacket(Pack);
9602
9509 } 9603 }
9510 9604
9511 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket) 9605 private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs
index 587579d..295a5e6 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Threading;
29using System.Collections.Generic; 30using System.Collections.Generic;
30using OpenMetaverse; 31using OpenMetaverse;
31using OpenMetaverse.Imaging; 32using OpenMetaverse.Imaging;
@@ -96,46 +97,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP
96 97
97 J2KImage imgrequest = m_imagestore[newRequest.RequestedAssetID]; 98 J2KImage imgrequest = m_imagestore[newRequest.RequestedAssetID];
98 99
100 // This is the inbound request sequence number. We can ignore
101 // "old" ones.
102
99 if (newRequest.requestSequence > imgrequest.m_lastSequence) 103 if (newRequest.requestSequence > imgrequest.m_lastSequence)
100 { 104 {
105
101 imgrequest.m_lastSequence = newRequest.requestSequence; 106 imgrequest.m_lastSequence = newRequest.requestSequence;
102 107
103 //First of all, is this being killed? 108 //Check the priority
104 //if (newRequest.Priority == 0.0f && newRequest.DiscardLevel == -1)
105 //{
106 //Do nothing (leaving the if for future use)
107 //}
108 //else
109 //{
110 109
110 double priority = imgrequest.m_requestedPriority;
111 if (priority != newRequest.Priority)
112 {
113 //Remove the old priority
114 m_priorities.Remove(imgrequest.m_designatedPriorityKey);
115 //Assign a new unique priority
116 imgrequest.m_requestedPriority = newRequest.Priority;
117 imgrequest.m_designatedPriorityKey = AssignPriority(newRequest.RequestedAssetID, newRequest.Priority);
118 }
111 119
112 //Check the priority 120 //Update the requested discard level
113 double priority = imgrequest.m_requestedPriority; 121 imgrequest.m_requestedDiscardLevel = newRequest.DiscardLevel;
114 if (priority != newRequest.Priority)
115 {
116 //Remove the old priority
117 m_priorities.Remove(imgrequest.m_designatedPriorityKey);
118 //Assign a new unique priority
119 imgrequest.m_requestedPriority = newRequest.Priority;
120 imgrequest.m_designatedPriorityKey = AssignPriority(newRequest.RequestedAssetID, newRequest.Priority);
121 }
122 122
123 //Update the requested discard level 123 //Update the requested packet number
124 imgrequest.m_requestedDiscardLevel = newRequest.DiscardLevel; 124 imgrequest.m_requestedPacketNumber = newRequest.PacketNumber;
125 125
126 //Update the requested packet number 126 //Check if this will create an outstanding texture request
127 imgrequest.m_requestedPacketNumber = newRequest.PacketNumber; 127 bool activated = imgrequest.m_completedSendAtCurrentDiscardLevel;
128 //Run an update
128 129
129 //Check if this will create an outstanding texture request 130 imgrequest.RunUpdate();
130 bool activated = imgrequest.m_completedSendAtCurrentDiscardLevel;
131 //Run an update
132 imgrequest.RunUpdate();
133 if (activated && !imgrequest.m_completedSendAtCurrentDiscardLevel && imgrequest.m_decoded)
134 {
135 m_outstandingtextures++;
136 }
137 131
138 //} 132 if (activated && !imgrequest.m_completedSendAtCurrentDiscardLevel && imgrequest.m_decoded)
133 {
134 Interlocked.Increment(ref m_outstandingtextures);
135 }
139 } 136 }
140 } 137 }
141 else 138 else
@@ -198,10 +195,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
198 195
199 } 196 }
200 197
201 public void ProcessImageQueue(int count) 198 public bool ProcessImageQueue(int count, int maxpack)
202 { 199 {
200
203 // this can happen during Close() 201 // this can happen during Close()
204 if (m_client == null) return; 202 if (m_client == null)
203 return false;
205 204
206 //Count is the number of textures we want to process in one go. 205 //Count is the number of textures we want to process in one go.
207 //As part of this class re-write, that number will probably rise 206 //As part of this class re-write, that number will probably rise
@@ -214,7 +213,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
214 if (m_lastloopprocessed == 0) 213 if (m_lastloopprocessed == 0)
215 { 214 {
216 if (m_client.PacketHandler == null || m_client.PacketHandler.PacketQueue == null || m_client.PacketHandler.PacketQueue.TextureThrottle == null) 215 if (m_client.PacketHandler == null || m_client.PacketHandler.PacketQueue == null || m_client.PacketHandler.PacketQueue.TextureThrottle == null)
217 return; 216 return false;
218 //This is decent for a semi fast machine, but we'll calculate it more accurately based on time below 217 //This is decent for a semi fast machine, but we'll calculate it more accurately based on time below
219 threshold = m_client.PacketHandler.PacketQueue.TextureThrottle.Current / 6300; 218 threshold = m_client.PacketHandler.PacketQueue.TextureThrottle.Current / 6300;
220 m_lastloopprocessed = DateTime.Now.Ticks; 219 m_lastloopprocessed = DateTime.Now.Ticks;
@@ -239,10 +238,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
239 } 238 }
240 239
241 if (m_client.PacketHandler == null) 240 if (m_client.PacketHandler == null)
242 return; 241 return false;
243 242
244 if (m_client.PacketHandler.PacketQueue == null) 243 if (m_client.PacketHandler.PacketQueue == null)
245 return; 244 return false;
246 245
247 //First of all make sure our packet queue isn't above our threshold 246 //First of all make sure our packet queue isn't above our threshold
248 247
@@ -252,24 +251,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
252 { 251 {
253 bool justreset = false; 252 bool justreset = false;
254 253
255
256
257 for (int x = m_priorities.Count - 1; x > -1; x--) 254 for (int x = m_priorities.Count - 1; x > -1; x--)
258 { 255 {
259 256
260 J2KImage imagereq = m_imagestore[m_priorities.Values[x]]; 257 J2KImage imagereq = m_imagestore[m_priorities.Values[x]];
261 if (imagereq.m_decoded == true && !imagereq.m_completedSendAtCurrentDiscardLevel) 258 if (imagereq.m_decoded == true && !imagereq.m_completedSendAtCurrentDiscardLevel)
262 { 259 {
263
264 numCollected++; 260 numCollected++;
265 //SendPackets will send up to ten packets per cycle 261 //SendPackets will send up to ten packets per cycle
266 if (imagereq.SendPackets(m_client)) 262 if (imagereq.SendPackets(m_client, maxpack))
267 { 263 {
268 //Send complete 264 //Send complete
269 if (!imagereq.m_completedSendAtCurrentDiscardLevel) 265 if (!imagereq.m_completedSendAtCurrentDiscardLevel)
270 { 266 {
271 imagereq.m_completedSendAtCurrentDiscardLevel = true; 267 imagereq.m_completedSendAtCurrentDiscardLevel = true;
272 m_outstandingtextures--; 268 Interlocked.Decrement(ref m_outstandingtextures);
273 //Re-assign priority to bottom 269 //Re-assign priority to bottom
274 //Remove the old priority 270 //Remove the old priority
275 m_priorities.Remove(imagereq.m_designatedPriorityKey); 271 m_priorities.Remove(imagereq.m_designatedPriorityKey);
@@ -310,13 +306,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
310 306
311 justreset = true; //prevents us from getting stuck in a loop 307 justreset = true; //prevents us from getting stuck in a loop
312 } 308 }
313
314
315 } 309 }
316 } 310 }
317 311
318 312 return m_outstandingtextures != 0;
319
320 } 313 }
321 314
322 //Faux destructor 315 //Faux destructor
diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example
index 91f86c5..5f2b46a 100644
--- a/bin/OpenSim.ini.example
+++ b/bin/OpenSim.ini.example
@@ -1208,12 +1208,15 @@
1208 1208
1209[LLClient] 1209[LLClient]
1210 ; Resend packets markes as reliable until they are received 1210 ; Resend packets markes as reliable until they are received
1211 ;
1211 ;ReliableIsImportant = false 1212 ;ReliableIsImportant = false
1212 1213
1213 ; Maximum number of times to resend packets marked reliable 1214 ; Maximum number of times to resend packets marked reliable
1215 ;
1214 ;MaxReliableResends = 3 1216 ;MaxReliableResends = 3
1215 1217
1216 ; Configures how ObjectUpdates are compressed. 1218 ; Configures how ObjectUpdates are compressed.
1219 ;
1217 ;TerseUpdatesPerPacket=10 1220 ;TerseUpdatesPerPacket=10
1218 ;FullUpdatesPerPacket=14 1221 ;FullUpdatesPerPacket=14
1219 ;TerseUpdateRate=10 1222 ;TerseUpdateRate=10
@@ -1221,6 +1224,22 @@
1221 1224
1222 ;PacketMTU = 1400 1225 ;PacketMTU = 1400
1223 1226
1227 ; TextureUpdateRate (mS) determines how many times per second
1228 ; texture send processing will occur. The default is 100mS.
1229 ;
1230 ;TextureRequestRate = 100
1231
1232 ; TextureSendLimit determines how many different textures
1233 ; will be considered on each cycle. Textures are selected
1234 ; by priority. The old mechanism specified a value of 10 for
1235 ; this parameter.
1236 ;
1237 ;TextureSendLimit = 10
1238
1239 ; TextureDataLimit determines how many packets will be sent for
1240 ; each of the selected textures. Default is 5.
1241 ;
1242 ;TextureDataLimit = 5
1224 1243
1225;; 1244;;
1226;; These are defatuls that are overwritten below in [Architecture]. 1245;; These are defatuls that are overwritten below in [Architecture].