diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs | 214 |
1 files changed, 88 insertions, 126 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs index d641b6c..facfb9d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs | |||
@@ -50,43 +50,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
50 | } | 50 | } |
51 | 51 | ||
52 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 52 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
53 | private bool m_shuttingdown = false; | 53 | private bool m_shuttingdown; |
54 | private long m_lastloopprocessed = 0; | 54 | private long m_lastloopprocessed; |
55 | private AssetBase m_missingImage = null; | 55 | private AssetBase m_missingImage; |
56 | |||
57 | private LLClientView m_client; //Client we're assigned to | 56 | private LLClientView m_client; //Client we're assigned to |
58 | private IAssetService m_assetCache; //Asset Cache | 57 | private IAssetService m_assetCache; //Asset Cache |
59 | private IJ2KDecoder m_j2kDecodeModule; //Our J2K module | 58 | private IJ2KDecoder m_j2kDecodeModule; //Our J2K module |
60 | private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer()); | 59 | private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer()); |
60 | private object m_syncRoot = new object(); | ||
61 | |||
62 | public LLClientView Client { get { return m_client; } } | ||
63 | public AssetBase MissingImage { get { return m_missingImage; } } | ||
61 | 64 | ||
62 | public LLImageManager(LLClientView client, IAssetService pAssetCache, IJ2KDecoder pJ2kDecodeModule) | 65 | public LLImageManager(LLClientView client, IAssetService pAssetCache, IJ2KDecoder pJ2kDecodeModule) |
63 | { | 66 | { |
64 | m_client = client; | 67 | m_client = client; |
65 | m_assetCache = pAssetCache; | 68 | m_assetCache = pAssetCache; |
69 | |||
66 | if (pAssetCache != null) | 70 | if (pAssetCache != null) |
67 | m_missingImage = pAssetCache.Get("5748decc-f629-461c-9a36-a35a221fe21f"); | 71 | m_missingImage = pAssetCache.Get("5748decc-f629-461c-9a36-a35a221fe21f"); |
68 | else | 72 | |
69 | m_log.Error("[ClientView] - couldn't set missing image asset, falling back to missing image packet. This is known to crash the client"); | 73 | if (m_missingImage == null) |
74 | m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client"); | ||
70 | 75 | ||
71 | m_j2kDecodeModule = pJ2kDecodeModule; | 76 | m_j2kDecodeModule = pJ2kDecodeModule; |
72 | } | 77 | } |
73 | 78 | ||
74 | public LLClientView Client | 79 | /// <summary> |
75 | { | 80 | /// Handles an incoming texture request or update to an existing texture request |
76 | get { return m_client; } | 81 | /// </summary> |
77 | } | 82 | /// <param name="newRequest"></param> |
78 | |||
79 | public AssetBase MissingImage | ||
80 | { | ||
81 | get { return m_missingImage; } | ||
82 | } | ||
83 | |||
84 | public void EnqueueReq(TextureRequestArgs newRequest) | 83 | public void EnqueueReq(TextureRequestArgs newRequest) |
85 | { | 84 | { |
86 | //newRequest is the properties of our new texture fetch request. | ||
87 | //Basically, here is where we queue up "new" requests.. | ||
88 | // .. or modify existing requests to suit. | ||
89 | |||
90 | //Make sure we're not shutting down.. | 85 | //Make sure we're not shutting down.. |
91 | if (!m_shuttingdown) | 86 | if (!m_shuttingdown) |
92 | { | 87 | { |
@@ -125,21 +120,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
125 | imgrequest.DiscardLevel = newRequest.DiscardLevel; | 120 | imgrequest.DiscardLevel = newRequest.DiscardLevel; |
126 | 121 | ||
127 | //Update the requested packet number | 122 | //Update the requested packet number |
128 | imgrequest.StartPacket = newRequest.PacketNumber; | 123 | imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber); |
129 | 124 | ||
130 | //Update the requested priority | 125 | //Update the requested priority |
131 | imgrequest.Priority = newRequest.Priority; | 126 | imgrequest.Priority = newRequest.Priority; |
132 | try | 127 | UpdateImageInQueue(imgrequest); |
133 | { | ||
134 | lock (m_priorityQueue) | ||
135 | m_priorityQueue.Replace(imgrequest.PriorityQueueHandle, imgrequest); | ||
136 | } | ||
137 | catch (Exception) | ||
138 | { | ||
139 | imgrequest.PriorityQueueHandle = null; | ||
140 | lock (m_priorityQueue) | ||
141 | m_priorityQueue.Add(ref imgrequest.PriorityQueueHandle, imgrequest); | ||
142 | } | ||
143 | 128 | ||
144 | //Run an update | 129 | //Run an update |
145 | imgrequest.RunUpdate(); | 130 | imgrequest.RunUpdate(); |
@@ -159,31 +144,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
159 | // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority); | 144 | // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority); |
160 | 145 | ||
161 | imgrequest = new J2KImage(this); | 146 | imgrequest = new J2KImage(this); |
162 | |||
163 | //Assign our decoder module | ||
164 | imgrequest.J2KDecoder = m_j2kDecodeModule; | 147 | imgrequest.J2KDecoder = m_j2kDecodeModule; |
165 | |||
166 | //Assign our asset cache module | ||
167 | imgrequest.AssetService = m_assetCache; | 148 | imgrequest.AssetService = m_assetCache; |
168 | |||
169 | //Assign the requested discard level | ||
170 | imgrequest.DiscardLevel = newRequest.DiscardLevel; | 149 | imgrequest.DiscardLevel = newRequest.DiscardLevel; |
171 | 150 | imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber); | |
172 | //Assign the requested packet number | ||
173 | imgrequest.StartPacket = newRequest.PacketNumber; | ||
174 | |||
175 | //Assign the requested priority | ||
176 | imgrequest.Priority = newRequest.Priority; | 151 | imgrequest.Priority = newRequest.Priority; |
177 | |||
178 | //Assign the asset uuid | ||
179 | imgrequest.TextureID = newRequest.RequestedAssetID; | 152 | imgrequest.TextureID = newRequest.RequestedAssetID; |
180 | |||
181 | //Assign the requested priority | ||
182 | imgrequest.Priority = newRequest.Priority; | 153 | imgrequest.Priority = newRequest.Priority; |
183 | 154 | ||
184 | //Add this download to the priority queue | 155 | //Add this download to the priority queue |
185 | lock (m_priorityQueue) | 156 | AddImageToQueue(imgrequest); |
186 | m_priorityQueue.Add(ref imgrequest.PriorityQueueHandle, imgrequest); | ||
187 | 157 | ||
188 | //Run an update | 158 | //Run an update |
189 | imgrequest.RunUpdate(); | 159 | imgrequest.RunUpdate(); |
@@ -194,105 +164,97 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
194 | 164 | ||
195 | public bool ProcessImageQueue(int count, int maxpack) | 165 | public bool ProcessImageQueue(int count, int maxpack) |
196 | { | 166 | { |
197 | lock (this) | 167 | J2KImage imagereq; |
168 | int numCollected = 0; | ||
169 | |||
170 | lock (m_syncRoot) | ||
198 | { | 171 | { |
199 | //count is the number of textures we want to process in one go. | 172 | m_lastloopprocessed = DateTime.Now.Ticks; |
200 | //As part of this class re-write, that number will probably rise | ||
201 | //since we're processing in a more efficient manner. | ||
202 | 173 | ||
203 | // this can happen during Close() | 174 | // This can happen during Close() |
204 | if (m_client == null) | 175 | if (m_client == null || m_client.PacketHandler == null || m_client.PacketHandler.PacketQueue == null) |
205 | return false; | 176 | return false; |
206 | 177 | ||
207 | int numCollected = 0; | 178 | while ((imagereq = GetHighestPriorityImage()) != null) |
208 | |||
209 | //Calculate our threshold | ||
210 | int threshold; | ||
211 | if (m_lastloopprocessed == 0) | ||
212 | { | ||
213 | if (m_client.PacketHandler == null || m_client.PacketHandler.PacketQueue == null || m_client.PacketHandler.PacketQueue.TextureThrottle == null) | ||
214 | return false; | ||
215 | //This is decent for a semi fast machine, but we'll calculate it more accurately based on time below | ||
216 | threshold = m_client.PacketHandler.PacketQueue.TextureThrottle.Current / 6300; | ||
217 | m_lastloopprocessed = DateTime.Now.Ticks; | ||
218 | } | ||
219 | else | ||
220 | { | 179 | { |
221 | double throttleseconds = ((double)DateTime.Now.Ticks - (double)m_lastloopprocessed) / (double)TimeSpan.TicksPerSecond; | 180 | if (imagereq.IsDecoded == true) |
222 | throttleseconds = throttleseconds * m_client.PacketHandler.PacketQueue.TextureThrottle.Current; | ||
223 | |||
224 | //Average of 1000 bytes per packet | ||
225 | throttleseconds = throttleseconds / 1000; | ||
226 | |||
227 | //Safe-zone multiplier of 2.0 | ||
228 | threshold = (int)(throttleseconds * 2.0); | ||
229 | m_lastloopprocessed = DateTime.Now.Ticks; | ||
230 | |||
231 | } | ||
232 | |||
233 | if (m_client.PacketHandler == null) | ||
234 | return false; | ||
235 | |||
236 | if (m_client.PacketHandler.PacketQueue == null) | ||
237 | return false; | ||
238 | |||
239 | if (threshold < 10) | ||
240 | threshold = 10; | ||
241 | |||
242 | //Uncomment this to see what the texture stack is doing | ||
243 | //m_log.Debug("Queue: " + m_client.PacketHandler.PacketQueue.getQueueCount(ThrottleOutPacketType.Texture).ToString() + " Threshold: " + threshold.ToString() + " outstanding: " + m_outstandingtextures.ToString()); | ||
244 | if (true) //m_client.PacketHandler.PacketQueue.GetQueueCount(ThrottleOutPacketType.Texture) < threshold) | ||
245 | { | ||
246 | while (m_priorityQueue.Count > 0) | ||
247 | { | 181 | { |
248 | J2KImage imagereq = null; | 182 | ++numCollected; |
249 | lock (m_priorityQueue) | ||
250 | imagereq = m_priorityQueue.FindMax(); | ||
251 | 183 | ||
252 | if (imagereq.IsDecoded == true) | 184 | if (imagereq.SendPackets(m_client, maxpack)) |
253 | { | 185 | { |
254 | // we need to test this here now that we are dropping assets | 186 | // Send complete. Destroy any knowledge of this transfer |
255 | if (!imagereq.HasAsset) | 187 | RemoveImageFromQueue(imagereq); |
256 | { | ||
257 | m_log.WarnFormat("[LLIMAGE MANAGER]: Re-requesting the image asset {0}", imagereq.TextureID); | ||
258 | imagereq.RunUpdate(); | ||
259 | continue; | ||
260 | } | ||
261 | |||
262 | ++numCollected; | ||
263 | |||
264 | //SendPackets will send up to ten packets per cycle | ||
265 | if (imagereq.SendPackets(m_client, maxpack)) | ||
266 | { | ||
267 | // Send complete. Destroy any knowledge of this transfer | ||
268 | try | ||
269 | { | ||
270 | lock (m_priorityQueue) | ||
271 | m_priorityQueue.Delete(imagereq.PriorityQueueHandle); | ||
272 | } | ||
273 | catch (Exception) { } | ||
274 | } | ||
275 | } | 188 | } |
276 | |||
277 | if (numCollected == count) | ||
278 | break; | ||
279 | } | 189 | } |
280 | } | ||
281 | 190 | ||
282 | return m_priorityQueue.Count > 0; | 191 | if (numCollected == count) |
192 | break; | ||
193 | } | ||
283 | } | 194 | } |
195 | |||
196 | return m_priorityQueue.Count > 0; | ||
284 | } | 197 | } |
285 | 198 | ||
286 | //Faux destructor | 199 | //Faux destructor |
287 | public void Close() | 200 | public void Close() |
288 | { | 201 | { |
289 | |||
290 | m_shuttingdown = true; | 202 | m_shuttingdown = true; |
291 | m_j2kDecodeModule = null; | 203 | m_j2kDecodeModule = null; |
292 | m_assetCache = null; | 204 | m_assetCache = null; |
293 | m_client = null; | 205 | m_client = null; |
294 | } | 206 | } |
295 | 207 | ||
208 | #region Priority Queue Helpers | ||
209 | |||
210 | J2KImage GetHighestPriorityImage() | ||
211 | { | ||
212 | J2KImage image = null; | ||
213 | |||
214 | if (m_priorityQueue.Count > 0) | ||
215 | { | ||
216 | try | ||
217 | { | ||
218 | lock (m_priorityQueue) | ||
219 | image = m_priorityQueue.FindMax(); | ||
220 | } | ||
221 | catch (Exception) { } | ||
222 | } | ||
223 | |||
224 | return image; | ||
225 | } | ||
226 | |||
227 | void AddImageToQueue(J2KImage image) | ||
228 | { | ||
229 | image.PriorityQueueHandle = null; | ||
230 | |||
231 | lock (m_priorityQueue) | ||
232 | m_priorityQueue.Add(ref image.PriorityQueueHandle, image); | ||
233 | } | ||
234 | |||
235 | void RemoveImageFromQueue(J2KImage image) | ||
236 | { | ||
237 | try | ||
238 | { | ||
239 | lock (m_priorityQueue) | ||
240 | m_priorityQueue.Delete(image.PriorityQueueHandle); | ||
241 | } | ||
242 | catch (Exception) { } | ||
243 | } | ||
244 | |||
245 | void UpdateImageInQueue(J2KImage image) | ||
246 | { | ||
247 | lock (m_priorityQueue) | ||
248 | { | ||
249 | try { m_priorityQueue.Replace(image.PriorityQueueHandle, image); } | ||
250 | catch (Exception) | ||
251 | { | ||
252 | image.PriorityQueueHandle = null; | ||
253 | m_priorityQueue.Add(ref image.PriorityQueueHandle, image); | ||
254 | } | ||
255 | } | ||
256 | } | ||
296 | 257 | ||
258 | #endregion Priority Queue Helpers | ||
297 | } | 259 | } |
298 | } | 260 | } |