2010-04-16 24 views
5

Tôi hiện đang có một trò chơi chụp ảnh lớn, dễ dàng lớn hơn 1MB, để làm nền. Tôi biết chính xác khi nào quá trình chuyển đổi này diễn ra, vì vậy tôi đã tạo một lớp bộ nạp để xử lý tải những hình ảnh lớn này trong nền, nhưng khi tôi tải các hình ảnh, nó vẫn đóng băng luồng chính nơi bản vẽ diễn ra. Kể từ khi mã này chạy trên 360 tôi di chuyển các chủ đề đến chủ đề phần cứng thứ 4, nhưng điều đó dường như không giúp đỡ. Dưới đây là lớp tôi đang sử dụng. Bất kỳ suy nghĩ nào về lý do tại sao trình quản lý nội dung mới của tôi nên nằm trong chủ đề riêng của nó đang làm gián đoạn quá trình vẽ trong chuỗi chính của tôi sẽ được đánh giá cao.XNA Xbox 360 Trình quản lý nội dung Chủ đề đóng băng Rút chủ đề

namespace FileSystem 
{ 
/// <summary> 
/// This is used to reference how many objects reference this texture. 
/// Everytime someone references a texture we increase the iNumberOfReferences. 
/// When a class calls remove on a specific texture we check to see if anything 
/// else is referencing the class, if it is we don't remove it. If there isn't 
/// anything referencing the texture its safe to dispose of. 
/// </summary> 
class TextureContainer 
{ 
    public uint uiNumberOfReferences = 0; 
    public Texture2D texture; 
} 

/// <summary> 
/// This class loads all the files from the Content. 
/// </summary> 
static class FileManager 
{ 
    static Microsoft.Xna.Framework.Content.ContentManager Content; 
    static EventWaitHandle wh = new AutoResetEvent(false); 
    static Dictionary<string, TextureContainer> Texture2DResourceDictionary; 
    static List<Texture2D> TexturesToDispose; 
    static List<String> TexturesToLoad; 
    static int iProcessor = 4; 

    private static object threadMutex = new object(); 
    private static object Texture2DMutex = new object(); 
    private static object loadingMutex = new object(); 

    private static bool bLoadingTextures = false; 

    /// <summary> 
    /// Returns if we are loading textures or not. 
    /// </summary> 
    public static bool LoadingTexture 
    { 
     get { 
       lock (loadingMutex) 
       { 
        return bLoadingTextures; 
       } 
      } 
    } 

    /// <summary> 
    /// Since this is an static class. This is the constructor for the file loadeder. This is the version 
    /// for the Xbox 360. 
    /// </summary> 
    /// <param name="_Content"></param> 
    public static void Initalize(IServiceProvider serviceProvider, string rootDirectory, int _iProcessor) 
    { 
     Content = new Microsoft.Xna.Framework.Content.ContentManager(serviceProvider, rootDirectory); 
     Texture2DResourceDictionary = new Dictionary<string, TextureContainer>(); 
     TexturesToDispose = new List<Texture2D>(); 
     iProcessor = _iProcessor; 
     CreateThread(); 
    } 

    /// <summary> 
    /// Since this is an static class. This is the constructor for the file loadeder. 
    /// </summary> 
    /// <param name="_Content"></param> 
    public static void Initalize(IServiceProvider serviceProvider, string rootDirectory) 
    { 
     Content = new Microsoft.Xna.Framework.Content.ContentManager(serviceProvider, rootDirectory); 
     Texture2DResourceDictionary = new Dictionary<string, TextureContainer>(); 
     TexturesToDispose = new List<Texture2D>(); 
     CreateThread(); 
    } 

    /// <summary> 
    /// Creates the thread incase we wanted to set up some parameters 
    /// Outside of the constructor. 
    /// </summary> 
    static public void CreateThread() 
    { 
     Thread t = new Thread(new ThreadStart(StartThread)); 
     t.Start(); 

    } 

    // This is the function that we thread. 
    static public void StartThread() 
    { 
     //BBSThreadClass BBSTC = (BBSThreadClass)_oData; 
     FileManager.Execute(); 
    } 

    /// <summary> 
    /// This thread shouldn't be called by the outside world. 
    /// It allows the File Manager to loop. 
    /// </summary> 
    static private void Execute() 
    { 
     // Make sure our thread is on the correct processor on the XBox 360. 
#if WINDOWS 
#else 
     Thread.CurrentThread.SetProcessorAffinity(new int[] { iProcessor }); 
     Thread.CurrentThread.IsBackground = true; 
#endif 
     // This loop will load textures into ram for us away from the main thread. 
     while (true) 
     { 
      wh.WaitOne(); 
      // Locking down our data while we process it. 
      lock (threadMutex) 
      { 
       lock (loadingMutex) 
       { 
        bLoadingTextures = true; 
       } 
       bool bContainsKey = false; 
       for (int con = 0; con < TexturesToLoad.Count; con++) 
       { 
        // If we have already loaded the texture into memory reference 
        // the one in the dictionary. 
        lock (Texture2DMutex) 
        { 
         bContainsKey = Texture2DResourceDictionary.ContainsKey(TexturesToLoad[con]); 
        } 

        if (bContainsKey) 
        { 
         // Do nothing 
        } 
        // Otherwise load it into the dictionary and then reference the 
        // copy in the dictionary 
        else 
        { 
         TextureContainer TC = new TextureContainer(); 
         TC.uiNumberOfReferences = 1; // We start out with 1 referece. 
         // Loading the texture into memory. 

         try 
         { 
          TC.texture = Content.Load<Texture2D>(TexturesToLoad[con]); 

          // This is passed into the dictionary, thus there is only one copy of 
          // the texture in memory. 

          // There is an issue with Sprite Batch and disposing textures. 
          // This will have to wait until its figured out. 
          lock (Texture2DMutex) 
          { 
           bContainsKey = Texture2DResourceDictionary.ContainsKey(TexturesToLoad[con]); 
           Texture2DResourceDictionary.Add(TexturesToLoad[con], TC); 
          } 
          // We don't have the find the reference to the container since we 
          // already have it. 
         } 
         // Occasionally our texture will already by loaded by another thread while 
         // this thread is operating. This mainly happens on the first level. 
         catch (Exception e) 
         { 
          // If this happens we don't worry about it since this thread only loads 
          // texture data and if its already there we don't need to load it. 
         } 
        } 
        Thread.Sleep(100); 
       } 
      } 
      lock (loadingMutex) 
      { 
       bLoadingTextures = false; 
      } 
     } 
    } 

    static public void LoadTextureList(List<string> _textureList) 
    { 
     // Ensuring that we can't creating threading problems. 
     lock (threadMutex) 
     { 
      TexturesToLoad = _textureList; 
     } 
     wh.Set(); 
    } 

    /// <summary> 
    /// This loads a 2D texture which represents a 2D grid of Texels. 
    /// </summary> 
    /// <param name="_textureName">The name of the picture you wish to load.</param> 
    /// <returns>Holds the image data.</returns> 
    public static Texture2D LoadTexture2D(string _textureName) 
    { 
     TextureContainer temp; 
     lock (Texture2DMutex) 
     { 
      bool bContainsKey = false; 
      // If we have already loaded the texture into memory reference 
      // the one in the dictionary. 
      lock (Texture2DMutex) 
      { 
       bContainsKey = Texture2DResourceDictionary.ContainsKey(_textureName); 

       if (bContainsKey) 
       { 
        temp = Texture2DResourceDictionary[_textureName]; 
        temp.uiNumberOfReferences++; // Incrementing the number of references 
       } 
       // Otherwise load it into the dictionary and then reference the 
       // copy in the dictionary 
       else 
       { 
        TextureContainer TC = new TextureContainer(); 
        TC.uiNumberOfReferences = 1; // We start out with 1 referece. 
        // Loading the texture into memory. 
        try 
        { 
         TC.texture = Content.Load<Texture2D>(_textureName); 

         // This is passed into the dictionary, thus there is only one copy of 
         // the texture in memory. 
        } 
        // Occasionally our texture will already by loaded by another thread while 
        // this thread is operating. This mainly happens on the first level. 
        catch(Exception e) 
        { 
         temp = Texture2DResourceDictionary[_textureName]; 
         temp.uiNumberOfReferences++; // Incrementing the number of references 
        } 

        // There is an issue with Sprite Batch and disposing textures. 
        // This will have to wait until its figured out. 
        Texture2DResourceDictionary.Add(_textureName, TC); 

        // We don't have the find the reference to the container since we 
        // already have it. 
        temp = TC; 
       } 
      } 
     } 
     // Return a reference to the texture 
     return temp.texture; 
    } 

    /// <summary> 
    /// Go through our dictionary and remove any references to the 
    /// texture passed in. 
    /// </summary> 
    /// <param name="texture">Texture to remove from texture dictionary.</param> 
    public static void RemoveTexture2D(Texture2D texture) 
    { 
     foreach (KeyValuePair<string, TextureContainer> pair in Texture2DResourceDictionary) 
     { 
      // Do our references match? 
      if (pair.Value.texture == texture) 
      { 
       // Only one object or less holds a reference to the 
       // texture. Logically it should be safe to remove. 
       if (pair.Value.uiNumberOfReferences <= 1) 
       { 
        // Grabing referenc to texture 
        TexturesToDispose.Add(pair.Value.texture); 
        // We are about to release the memory of the texture, 
        // thus we make sure no one else can call this member 
        // in the dictionary. 
        Texture2DResourceDictionary.Remove(pair.Key); 
        // Once we have removed the texture we don't want to create an exception. 
        // So we will stop looking in the list since it has changed. 
        break; 
       } 
       // More than one Object has a reference to this texture. 
       // So we will not be removing it from memory and instead 
       // simply marking down the number of references by 1. 
       else 
       { 
        pair.Value.uiNumberOfReferences--; 
       } 
      } 
     } 
    } 

    /*public static void DisposeTextures() 
    { 
     int Count = TexturesToDispose.Count; 
     // If there are any textures to dispose of. 
     if (Count > 0) 
     { 
      for (int con = 0; con < TexturesToDispose.Count; con++) 
      { 
       // =!THIS REMOVES THE TEXTURE FROM MEMORY!= 
       // This is not like a normal dispose. This will actually 
       // remove the object from memory. Texture2D is inherited 
       // from GraphicsResource which removes it self from 
       // memory on dispose. Very nice for game efficency, 
       // but "dangerous" in managed land. 
       Texture2D Temp = TexturesToDispose[con]; 
       Temp.Dispose(); 
      } 
      // Remove textures we've already disposed of. 
      TexturesToDispose.Clear(); 
     } 
    }*/ 

    /// <summary> 
    /// This loads a 2D texture which represnets a font. 
    /// </summary> 
    /// <param name="_textureName">The name of the font you wish to load.</param> 
    /// <returns>Holds the font data.</returns> 
    public static SpriteFont LoadFont(string _fontName) 
    { 
     SpriteFont temp = Content.Load<SpriteFont>(_fontName); 
     return temp; 
    } 

    /// <summary> 
    /// This loads an XML document. 
    /// </summary> 
    /// <param name="_textureName">The name of the XML document you wish to load.</param> 
    /// <returns>Holds the XML data.</returns> 
    public static XmlDocument LoadXML(string _fileName) 
    { 
     XmlDocument temp = Content.Load<XmlDocument>(_fileName); 
     return temp; 
    } 

    /// <summary> 
    /// This loads a sound file. 
    /// </summary> 
    /// <param name="_fileName"></param> 
    /// <returns></returns> 
    public static SoundEffect LoadSound(string _fileName) 
    { 
     SoundEffect temp = Content.Load<SoundEffect>(_fileName); 
     return temp; 
    } 
} 
} 

Trả lời

2

Từ bài viết trên blog: Lock Contention during Load Screen Animations bởi Shawn Hargreaves

Dưới đây là rồng! Mã trên sẽ hoạt động, nhưng có trách nhiệm làm cho số của bạn tải chậm hơn hàng trăm lần.

Lý do là mỗi khi bạn chạm vào thiết bị đồ họa từ một thread khác nhau , khuôn khổ mất ra một phần quan trọng, để tránh heisenbadness. Nếu hình ảnh động không ngừng được vẽ lại, các chủ đề hoạt hình sẽ khá nhiều luôn sở hữu khóa này, vì vậy bất cứ lúc nào tải của bạn chức năng muốn tạo ra một đồ họa tài nguyên như một kết cấu, đỉnh đệm, hoặc đổ bóng, nó phải chờ đợi cho đến khi chuỗi hoạt ảnh giải phóng nó. có thể mất một lúc nếu hoạt ảnh chỉ liên tục lặp qua cùng một đoạn mã vẽ!

Giải pháp là để chậm chủ đề hoạt hình của bạn bằng cách chèn một giấc ngủ gọi, mà dừng nó hogging thiết bị đồ họa.

Trong trường hợp của bạn, vì bạn đang tải kết cấu liền kề rất lớn, bạn có thể chỉ cần thiết kế lại tính năng tải của mình xảy ra khi người dùng không cần xem bất kỳ hoạt ảnh nào vì bạn mong đợi sẽ có một cái khóa.

+0

Tuy nhiên, khóa này không khóa mọi điểm vẽ? Tôi không thực sự chuyển đổi kết cấu trong bản vẽ chỉ vẽ từ cùng một con trỏ đã có trong bộ nhớ. – Alikar

+0

Nhưng vấn đề là trong khi bạn đang tải các kết cấu lớn hơn, nó khóa thiết bị đồ họa, khiến cho phương pháp vẽ phải chờ cho đến khi tải xong kết cấu –

1

Nếu không thấy phần còn lại của mã thì khó nói, nhưng tôi đoán là bạn có tranh chấp ở đâu đó. Tôi đã làm một thử nghiệm nhanh chóng tải 10 mô hình lớn (khoảng 5 giây tải thời gian) và tôi đã có thể tải chúng trên một sợi riêng biệt mà không cần tạm dừng các chủ đề chính.

0

Vấn đề là tôi tải một lượng lớn đồ họa nhỏ hơn trong chuỗi chính. Tôi đã thêm chúng vào danh sách để tải trong chuỗi và các vấn đề đã biến mất.

Vì vậy, các câu trả lời trước của bạn là chính xác. Tôi chỉ đơn giản là không sử dụng mọi thứ một cách chính xác.

Các vấn đề liên quan