Annotation of /trunk/DefaultRenderer/DefaultTexture.cs
Parent Directory
|
Revision Log
Revision 84 - (view) (download)
| 1 : | albert | 54 | using System; |
| 2 : | using System.Collections.Generic; | ||
| 3 : | using System.Linq; | ||
| 4 : | using System.Text; | ||
| 5 : | using Xenki.Framework; | ||
| 6 : | using OpenMetaverse; | ||
| 7 : | using System.Drawing; | ||
| 8 : | using System.IO; | ||
| 9 : | using System.Threading; | ||
| 10 : | using OpenMetaverse.Imaging; | ||
| 11 : | albert | 58 | using System.Runtime.InteropServices; |
| 12 : | albert | 54 | |
| 13 : | namespace Xenki.DefaultRenderer | ||
| 14 : | { | ||
| 15 : | |||
| 16 : | albert | 62 | public class DefaultTexture |
| 17 : | albert | 54 | { |
| 18 : | private event TextureDownloadFinished onDownloadFinished; | ||
| 19 : | |||
| 20 : | albert | 63 | string cachefolderPath = Mainform.TextureCacheFolder; |
| 21 : | albert | 54 | |
| 22 : | albert | 63 | string bmpFilePath = Mainform.TextureTempFolder; |
| 23 : | albert | 54 | |
| 24 : | //the textures have load in memory. | ||
| 25 : | // private readonly Dictionary<UUID, byte[]> CurruntTextures = new Dictionary<UUID, byte[]>(); | ||
| 26 : | |||
| 27 : | private Thread MainThread; | ||
| 28 : | // list of current requests in process | ||
| 29 : | private Dictionary<UUID, int> CurrentRequests; | ||
| 30 : | albert | 84 | //private ReaderWriterLockSlim rwCurrentRequests = new ReaderWriterLockSlim(); |
| 31 : | albert | 54 | private Queue<UUID> RequestQueue; |
| 32 : | albert | 84 | //private ReaderWriterLockSlim rwRequestQueue = new ReaderWriterLockSlim(); |
| 33 : | albert | 54 | private static AutoResetEvent[] resetEvents; |
| 34 : | |||
| 35 : | private static int[] threadpoolSlots; | ||
| 36 : | |||
| 37 : | // maximum allowed concurrent requests at once | ||
| 38 : | albert | 84 | const int MAX_TEXTURE_REQUESTS = 5; |
| 39 : | albert | 54 | |
| 40 : | private GridClient gridClient; | ||
| 41 : | |||
| 42 : | public GridClient GridClient | ||
| 43 : | { | ||
| 44 : | get { return gridClient; } | ||
| 45 : | set | ||
| 46 : | { | ||
| 47 : | gridClient = value; | ||
| 48 : | |||
| 49 : | gridClient.Settings.USE_TEXTURE_CACHE = true; | ||
| 50 : | albert | 55 | |
| 51 : | albert | 54 | if (Directory.Exists(cachefolderPath) == false) |
| 52 : | Directory.CreateDirectory(cachefolderPath); | ||
| 53 : | albert | 55 | if (Directory.Exists(bmpFilePath) == false) |
| 54 : | Directory.CreateDirectory(bmpFilePath); | ||
| 55 : | albert | 54 | |
| 56 : | albert | 55 | gridClient.Throttle.Texture = 440000.0f; |
| 57 : | albert | 54 | gridClient.Settings.TEXTURE_CACHE_DIR = cachefolderPath; |
| 58 : | albert | 84 | gridClient.Settings.TEXTURE_CACHE_MAX_SIZE = 700;//Mb |
| 59 : | albert | 54 | } |
| 60 : | } | ||
| 61 : | private static readonly DefaultTexture singleton = new DefaultTexture(); | ||
| 62 : | |||
| 63 : | albert | 84 | |
| 64 : | albert | 54 | public static DefaultTexture SingleTextureManager() |
| 65 : | { | ||
| 66 : | return singleton; | ||
| 67 : | } | ||
| 68 : | |||
| 69 : | private DefaultTexture() | ||
| 70 : | { | ||
| 71 : | RequestQueue = new Queue<UUID>(); | ||
| 72 : | |||
| 73 : | CurrentRequests = new Dictionary<UUID, int>(MAX_TEXTURE_REQUESTS); | ||
| 74 : | |||
| 75 : | resetEvents = new AutoResetEvent[MAX_TEXTURE_REQUESTS]; | ||
| 76 : | threadpoolSlots = new int[MAX_TEXTURE_REQUESTS]; | ||
| 77 : | |||
| 78 : | // pre-configure autoreset events/download slots | ||
| 79 : | for (int i = 0; i < MAX_TEXTURE_REQUESTS; i++) | ||
| 80 : | { | ||
| 81 : | resetEvents[i] = new AutoResetEvent(false); | ||
| 82 : | threadpoolSlots[i] = -1; | ||
| 83 : | } | ||
| 84 : | } | ||
| 85 : | |||
| 86 : | public void StartDownload() | ||
| 87 : | { | ||
| 88 : | try | ||
| 89 : | { | ||
| 90 : | GridClient.Assets.OnImageReceived += new AssetManager.ImageReceivedCallback(Assets_OnImageReceived); | ||
| 91 : | |||
| 92 : | MainThread = new Thread(new ThreadStart(DownloadTextureThread)); | ||
| 93 : | MainThread.Start(); | ||
| 94 : | } | ||
| 95 : | catch (Exception er) | ||
| 96 : | { | ||
| 97 : | Logger.DebugLog(er.Message); | ||
| 98 : | } | ||
| 99 : | } | ||
| 100 : | |||
| 101 : | private void DownloadTextureThread() | ||
| 102 : | { | ||
| 103 : | int reqNbr; | ||
| 104 : | |||
| 105 : | while (true) | ||
| 106 : | { | ||
| 107 : | albert | 82 | lock (RequestQueue) |
| 108 : | albert | 84 | //rwRequestQueue.EnterUpgradeableReadLock(); |
| 109 : | albert | 54 | { |
| 110 : | albert | 82 | if (RequestQueue.Count > 0) |
| 111 : | albert | 54 | { |
| 112 : | albert | 82 | reqNbr = -1; |
| 113 : | // find available slot for reset event | ||
| 114 : | for (int i = 0; i < threadpoolSlots.Length; i++) | ||
| 115 : | albert | 54 | { |
| 116 : | albert | 82 | if (threadpoolSlots[i] == -1) |
| 117 : | { | ||
| 118 : | threadpoolSlots[i] = 1; | ||
| 119 : | reqNbr = i; | ||
| 120 : | break; | ||
| 121 : | } | ||
| 122 : | albert | 54 | } |
| 123 : | albert | 84 | |
| 124 : | albert | 82 | if (reqNbr != -1) |
| 125 : | { | ||
| 126 : | albert | 54 | |
| 127 : | albert | 82 | UUID requestID; |
| 128 : | albert | 84 | //rwRequestQueue.EnterWriteLock(); |
| 129 : | albert | 54 | requestID = RequestQueue.Dequeue(); |
| 130 : | albert | 84 | //rwRequestQueue.ExitWriteLock(); |
| 131 : | albert | 54 | |
| 132 : | albert | 82 | Logger.DebugLog(String.Format("Sending Worker thread new download request {0}", reqNbr)); |
| 133 : | ThreadPool.QueueUserWorkItem(new WaitCallback(textureRequestDoWork), new TaskInfo(requestID, reqNbr)); | ||
| 134 : | albert | 54 | |
| 135 : | albert | 84 | //rwRequestQueue.ExitUpgradeableReadLock(); |
| 136 : | albert | 54 | |
| 137 : | albert | 82 | continue; |
| 138 : | } | ||
| 139 : | albert | 54 | } |
| 140 : | } | ||
| 141 : | albert | 84 | // rwRequestQueue.ExitUpgradeableReadLock(); |
| 142 : | albert | 54 | |
| 143 : | albert | 63 | Thread.Sleep(500); |
| 144 : | albert | 54 | } |
| 145 : | |||
| 146 : | } | ||
| 147 : | |||
| 148 : | void textureRequestDoWork(Object threadContext) | ||
| 149 : | { | ||
| 150 : | TaskInfo ti = (TaskInfo)threadContext; | ||
| 151 : | |||
| 152 : | albert | 84 | //rwCurrentRequests.EnterWriteLock(); |
| 153 : | albert | 54 | lock (CurrentRequests) |
| 154 : | { | ||
| 155 : | if (CurrentRequests.ContainsKey(ti.RequestID)) | ||
| 156 : | { | ||
| 157 : | threadpoolSlots[ti.RequestNbr] = -1; | ||
| 158 : | return; | ||
| 159 : | } | ||
| 160 : | else | ||
| 161 : | { | ||
| 162 : | CurrentRequests.Add(ti.RequestID, ti.RequestNbr); | ||
| 163 : | } | ||
| 164 : | } | ||
| 165 : | albert | 84 | //rwCurrentRequests.ExitWriteLock(); |
| 166 : | albert | 54 | |
| 167 : | Logger.DebugLog(String.Format("Worker {0} Requesting {1}", ti.RequestNbr, ti.RequestID)); | ||
| 168 : | |||
| 169 : | resetEvents[ti.RequestNbr].Reset(); | ||
| 170 : | GridClient.Assets.RequestImage(ti.RequestID, ImageType.Normal); | ||
| 171 : | |||
| 172 : | // don't release this worker slot until texture is downloaded or timeout occurs | ||
| 173 : | albert | 84 | if (!resetEvents[ti.RequestNbr].WaitOne(30 * 1000, false)) |
| 174 : | { | ||
| 175 : | // Timed out | ||
| 176 : | Logger.Log("Worker " + ti.RequestNbr + " Timeout waiting for Texture " + ti.RequestID + " to Download", Helpers.LogLevel.Warning); | ||
| 177 : | albert | 54 | |
| 178 : | albert | 84 | //rwCurrentRequests.EnterWriteLock(); |
| 179 : | lock (CurrentRequests) | ||
| 180 : | CurrentRequests.Remove(ti.RequestID); | ||
| 181 : | //rwCurrentRequests.ExitWriteLock(); | ||
| 182 : | albert | 54 | |
| 183 : | albert | 84 | //rwRequestQueue.EnterWriteLock(); |
| 184 : | lock (RequestQueue) | ||
| 185 : | RequestQueue.Enqueue(ti.RequestID); | ||
| 186 : | //rwRequestQueue.ExitWriteLock(); | ||
| 187 : | } | ||
| 188 : | |||
| 189 : | albert | 54 | // free up this download slot |
| 190 : | threadpoolSlots[ti.RequestNbr] = -1; | ||
| 191 : | ti = null; | ||
| 192 : | } | ||
| 193 : | |||
| 194 : | private void Assets_OnImageReceived(ImageDownload image, AssetTexture asset) | ||
| 195 : | { | ||
| 196 : | if (image.Success) | ||
| 197 : | { | ||
| 198 : | albert | 83 | lock (objFileAccess) |
| 199 : | albert | 68 | if (File.Exists(Path.Combine(bmpFilePath, image.ID.ToString() + ".png")) == false) |
| 200 : | albert | 54 | { |
| 201 : | albert | 62 | SaveTexture2Image(image); |
| 202 : | albert | 54 | } |
| 203 : | } | ||
| 204 : | |||
| 205 : | if (onDownloadFinished != null) | ||
| 206 : | { | ||
| 207 : | onDownloadFinished(image.ID, image.Success); | ||
| 208 : | } | ||
| 209 : | } | ||
| 210 : | albert | 84 | |
| 211 : | albert | 60 | ManagedImage managedimg; |
| 212 : | Image img; Bitmap bitmap; | ||
| 213 : | albert | 58 | private void SaveTexture2Image(ImageDownload image) |
| 214 : | albert | 54 | { |
| 215 : | if (OpenJPEG.DecodeToImage(image.AssetData, out managedimg, out img)) | ||
| 216 : | { | ||
| 217 : | albert | 60 | bitmap = new Bitmap(img); |
| 218 : | albert | 83 | bitmap.Save(Path.Combine(bmpFilePath, image.ID.ToString() + ".png"), |
| 219 : | System.Drawing.Imaging.ImageFormat.Png); | ||
| 220 : | albert | 54 | } |
| 221 : | } | ||
| 222 : | |||
| 223 : | public ImageDownload RetireveTextureData(UUID textureID) | ||
| 224 : | { | ||
| 225 : | ImageDownload image =null; | ||
| 226 : | |||
| 227 : | if (gridClient.Assets.Cache.HasImage(textureID)) | ||
| 228 : | { | ||
| 229 : | image = gridClient.Assets.Cache.GetCachedImage(textureID); | ||
| 230 : | } | ||
| 231 : | else | ||
| 232 : | { | ||
| 233 : | albert | 84 | //rwCurrentRequests.EnterReadLock(); |
| 234 : | //rwRequestQueue.EnterWriteLock(); | ||
| 235 : | |||
| 236 : | albert | 54 | lock (RequestQueue) |
| 237 : | { | ||
| 238 : | // Make sure we aren't already downloading the texture | ||
| 239 : | if (!RequestQueue.Contains(textureID)&& !CurrentRequests.ContainsKey(textureID)) | ||
| 240 : | { | ||
| 241 : | RequestQueue.Enqueue(textureID); | ||
| 242 : | } | ||
| 243 : | } | ||
| 244 : | albert | 84 | |
| 245 : | //rwRequestQueue.ExitWriteLock(); | ||
| 246 : | // rwCurrentRequests.ExitReadLock(); | ||
| 247 : | albert | 54 | } |
| 248 : | |||
| 249 : | return image; | ||
| 250 : | } | ||
| 251 : | |||
| 252 : | public void RequestTexture(UUID textureID) | ||
| 253 : | albert | 84 | { |
| 254 : | // lock (objFileAccess) | ||
| 255 : | albert | 54 | { |
| 256 : | albert | 84 | //if (File.Exists(Path.Combine(bmpFilePath, textureID.ToString() + ".png")) == true) |
| 257 : | // return; | ||
| 258 : | albert | 83 | |
| 259 : | albert | 84 | if (gridClient.Assets.Cache.HasImage(textureID) == false) |
| 260 : | albert | 54 | { |
| 261 : | albert | 84 | |
| 262 : | //rwRequestQueue.EnterWriteLock(); | ||
| 263 : | //rwCurrentRequests.EnterReadLock(); | ||
| 264 : | lock (RequestQueue) | ||
| 265 : | albert | 54 | { |
| 266 : | albert | 84 | // Make sure we aren't already downloading the texture |
| 267 : | if (!CurrentRequests.ContainsKey(textureID) && !RequestQueue.Contains(textureID)) | ||
| 268 : | RequestQueue.Enqueue(textureID); | ||
| 269 : | albert | 54 | } |
| 270 : | albert | 84 | //rwCurrentRequests.ExitReadLock(); |
| 271 : | //rwRequestQueue.ExitWriteLock(); | ||
| 272 : | albert | 54 | } |
| 273 : | } | ||
| 274 : | } | ||
| 275 : | |||
| 276 : | object objFileAccess = new object(); | ||
| 277 : | |||
| 278 : | public TextureDownloadFinished OnDownloadFinished | ||
| 279 : | { | ||
| 280 : | get | ||
| 281 : | { | ||
| 282 : | return onDownloadFinished; | ||
| 283 : | } | ||
| 284 : | set | ||
| 285 : | { | ||
| 286 : | onDownloadFinished = value; | ||
| 287 : | } | ||
| 288 : | } | ||
| 289 : | } | ||
| 290 : | |||
| 291 : | class TaskInfo | ||
| 292 : | { | ||
| 293 : | public UUID RequestID; | ||
| 294 : | public int RequestNbr; | ||
| 295 : | |||
| 296 : | |||
| 297 : | public TaskInfo(UUID reqID, int reqNbr) | ||
| 298 : | { | ||
| 299 : | RequestID = reqID; | ||
| 300 : | RequestNbr = reqNbr; | ||
| 301 : | } | ||
| 302 : | } | ||
| 303 : | } |
| ViewVC Help | |
| Powered by ViewVC 1.0.0 |

