aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs257
1 files changed, 257 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
new file mode 100644
index 0000000..9e0db12
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLImageManager.cs
@@ -0,0 +1,257 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Threading;
30using System.Collections;
31using System.Collections.Generic;
32using System.Reflection;
33using OpenMetaverse;
34using OpenMetaverse.Imaging;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Services.Interfaces;
38using log4net;
39
40namespace OpenSim.Region.ClientStack.LindenUDP
41{
42 public class LLImageManager
43 {
44 private sealed class J2KImageComparer : IComparer<J2KImage>
45 {
46 public int Compare(J2KImage x, J2KImage y)
47 {
48 return x.Priority.CompareTo(y.Priority);
49 }
50 }
51
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 private bool m_shuttingdown;
54 private AssetBase m_missingImage;
55 private LLClientView m_client; //Client we're assigned to
56 private IAssetService m_assetCache; //Asset Cache
57 private IJ2KDecoder m_j2kDecodeModule; //Our J2K module
58 private C5.IntervalHeap<J2KImage> m_priorityQueue = new C5.IntervalHeap<J2KImage>(10, new J2KImageComparer());
59 private object m_syncRoot = new object();
60
61 public LLClientView Client { get { return m_client; } }
62 public AssetBase MissingImage { get { return m_missingImage; } }
63
64 public LLImageManager(LLClientView client, IAssetService pAssetCache, IJ2KDecoder pJ2kDecodeModule)
65 {
66 m_client = client;
67 m_assetCache = pAssetCache;
68
69 if (pAssetCache != null)
70 m_missingImage = pAssetCache.Get("5748decc-f629-461c-9a36-a35a221fe21f");
71
72 if (m_missingImage == null)
73 m_log.Error("[ClientView] - Couldn't set missing image asset, falling back to missing image packet. This is known to crash the client");
74
75 m_j2kDecodeModule = pJ2kDecodeModule;
76 }
77
78 /// <summary>
79 /// Handles an incoming texture request or update to an existing texture request
80 /// </summary>
81 /// <param name="newRequest"></param>
82 public void EnqueueReq(TextureRequestArgs newRequest)
83 {
84 //Make sure we're not shutting down..
85 if (!m_shuttingdown)
86 {
87 J2KImage imgrequest;
88
89 // Do a linear search for this texture download
90 lock (m_syncRoot)
91 m_priorityQueue.Find(delegate(J2KImage img) { return img.TextureID == newRequest.RequestedAssetID; }, out imgrequest);
92
93 if (imgrequest != null)
94 {
95 if (newRequest.DiscardLevel == -1 && newRequest.Priority == 0f)
96 {
97 //m_log.Debug("[TEX]: (CAN) ID=" + newRequest.RequestedAssetID);
98
99 try
100 {
101 lock (m_syncRoot)
102 m_priorityQueue.Delete(imgrequest.PriorityQueueHandle);
103 }
104 catch (Exception) { }
105 }
106 else
107 {
108 //m_log.DebugFormat("[TEX]: (UPD) ID={0}: D={1}, S={2}, P={3}",
109 // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority);
110
111 //Check the packet sequence to make sure this isn't older than
112 //one we've already received
113 if (newRequest.requestSequence > imgrequest.LastSequence)
114 {
115 //Update the sequence number of the last RequestImage packet
116 imgrequest.LastSequence = newRequest.requestSequence;
117
118 //Update the requested discard level
119 imgrequest.DiscardLevel = newRequest.DiscardLevel;
120
121 //Update the requested packet number
122 imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber);
123
124 //Update the requested priority
125 imgrequest.Priority = newRequest.Priority;
126 UpdateImageInQueue(imgrequest);
127
128 //Run an update
129 imgrequest.RunUpdate();
130 }
131 }
132 }
133 else
134 {
135 if (newRequest.DiscardLevel == -1 && newRequest.Priority == 0f)
136 {
137 //m_log.DebugFormat("[TEX]: (IGN) ID={0}: D={1}, S={2}, P={3}",
138 // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority);
139 }
140 else
141 {
142 //m_log.DebugFormat("[TEX]: (NEW) ID={0}: D={1}, S={2}, P={3}",
143 // newRequest.RequestedAssetID, newRequest.DiscardLevel, newRequest.PacketNumber, newRequest.Priority);
144
145 imgrequest = new J2KImage(this);
146 imgrequest.J2KDecoder = m_j2kDecodeModule;
147 imgrequest.AssetService = m_assetCache;
148 imgrequest.AgentID = m_client.AgentId;
149 imgrequest.InventoryAccessModule = m_client.Scene.RequestModuleInterface<IInventoryAccessModule>();
150 imgrequest.DiscardLevel = newRequest.DiscardLevel;
151 imgrequest.StartPacket = Math.Max(1, newRequest.PacketNumber);
152 imgrequest.Priority = newRequest.Priority;
153 imgrequest.TextureID = newRequest.RequestedAssetID;
154 imgrequest.Priority = newRequest.Priority;
155
156 //Add this download to the priority queue
157 AddImageToQueue(imgrequest);
158
159 //Run an update
160 imgrequest.RunUpdate();
161 }
162 }
163 }
164 }
165
166 public bool ProcessImageQueue(int packetsToSend)
167 {
168 int packetsSent = 0;
169
170 while (packetsSent < packetsToSend)
171 {
172 J2KImage image = GetHighestPriorityImage();
173
174 // If null was returned, the texture priority queue is currently empty
175 if (image == null)
176 return false;
177
178 if (image.IsDecoded)
179 {
180 int sent;
181 bool imageDone = image.SendPackets(m_client, packetsToSend - packetsSent, out sent);
182 packetsSent += sent;
183
184 // If the send is complete, destroy any knowledge of this transfer
185 if (imageDone)
186 RemoveImageFromQueue(image);
187 }
188 else
189 {
190 // TODO: This is a limitation of how LLImageManager is currently
191 // written. Undecoded textures should not be going into the priority
192 // queue, because a high priority undecoded texture will clog up the
193 // pipeline for a client
194 return true;
195 }
196 }
197
198 return m_priorityQueue.Count > 0;
199 }
200
201 /// <summary>
202 /// Faux destructor
203 /// </summary>
204 public void Close()
205 {
206 m_shuttingdown = true;
207 }
208
209 #region Priority Queue Helpers
210
211 J2KImage GetHighestPriorityImage()
212 {
213 J2KImage image = null;
214
215 lock (m_syncRoot)
216 {
217 if (m_priorityQueue.Count > 0)
218 {
219 try { image = m_priorityQueue.FindMax(); }
220 catch (Exception) { }
221 }
222 }
223 return image;
224 }
225
226 void AddImageToQueue(J2KImage image)
227 {
228 image.PriorityQueueHandle = null;
229
230 lock (m_syncRoot)
231 try { m_priorityQueue.Add(ref image.PriorityQueueHandle, image); }
232 catch (Exception) { }
233 }
234
235 void RemoveImageFromQueue(J2KImage image)
236 {
237 lock (m_syncRoot)
238 try { m_priorityQueue.Delete(image.PriorityQueueHandle); }
239 catch (Exception) { }
240 }
241
242 void UpdateImageInQueue(J2KImage image)
243 {
244 lock (m_syncRoot)
245 {
246 try { m_priorityQueue.Replace(image.PriorityQueueHandle, image); }
247 catch (Exception)
248 {
249 image.PriorityQueueHandle = null;
250 m_priorityQueue.Add(ref image.PriorityQueueHandle, image);
251 }
252 }
253 }
254
255 #endregion Priority Queue Helpers
256 }
257}