2010-05-19 75 views
1

在HLSL中,有沒有辦法限制編譯器使用的常量寄存器的數量?HLSL:在編譯時強制執行常量寄存器限制

具體地,如果餘有類似:

float4 foobar[300]; 

在vs_2_0頂點着色器,編譯器將歡快產生具有超過256個常量寄存器的作用。但是2.0頂點着色器只能保證可以訪問256個常量寄存器,所以當我嘗試使用這個效果時,它在運行時會以一種模糊和GPU依賴的方式失敗。我寧願讓它在編譯時失敗。

這個問題特別討厭,因爲編譯器本身在我要求的場景後面分配常量寄存器。我必須檢查大會,看看我是否超出限制。

理想情況下,我想在HLSL(我使用XNA內容管道)中做到這一點,但是如果有一個標誌可以傳遞給編譯器,那也會很有趣。

+0

好問題。自從DirectX開發人員掛在那裏以後,我還會在http://forums.xna.com/forums/27.aspx上發佈它。 – Stringer 2010-05-19 09:17:18

+0

謝謝,斯金格貝爾。我按照你的建議將它發佈到XNA論壇:http://forums.xna.com/forums/p/53856/326864.aspx – 2010-05-19 22:09:33

+0

另外:如果在HLSL或編譯器中沒有辦法做到這一點,有沒有通過編程方式來計算編譯着色器使用的常量寄存器的數量? (理想情況下使用XNA) – 2010-05-19 22:20:03

回答

1

根據Stringer Bell指出的反彙編方法,我掀起了一個小型的構建後工具來分析和檢查效果。被警告,這不是很漂亮。它專爲XNA 3.1設計,需要the XNA WinForms sampleServiceContainerGraphicsDeviceService類。在命令行上傳遞內容目錄路徑而不使用結尾斜槓。

class Program 
{ 
    const int maxRegisters = 256; // Sutiable for VS 2.0, not much else 
    static int retval = 0; 
    static string root; 
    static ContentManager content; 

    static void CheckFile(string path) 
    { 
     string name = path.Substring(root.Length+1, path.Length - (root.Length+1) - @".xnb".Length); 
     Effect effect; 
     try { effect = content.Load<Effect>(name); } 
     catch { return; } // probably not an Effect 
     string effectSource = effect.Disassemble(false); 

     int highest = -1; // highest register allocated 

     var matches = Regex.Matches(effectSource, @" c([0-9]+)"); // quick and dirty 
     foreach(Match match in matches) 
     { 
      int register = Int32.Parse(match.Groups[1].ToString()); 
      if(register > highest) 
       highest = register; 
     } 

     var parameters = Regex.Matches(effectSource, @"^ *// *[a-zA-Z_0-9]+ +c([0-9]+) +([0-9]+)", RegexOptions.Multiline); 
     foreach(Match match in parameters) 
     { 
      int register = Int32.Parse(match.Groups[1].ToString()) + Int32.Parse(match.Groups[2].ToString()) - 1; 
      if(register > highest) 
       highest = register; 
     } 

     if(highest+1 > maxRegisters) 
     { 
      Console.WriteLine("Error: Shader \"" + name + "\" uses " + (highest+1).ToString() + " constant registers, which is TOO MANY!"); 
      retval = 1; 
     } 
     else 
     { 
      Console.WriteLine("Shader \"" + name + "\" uses " + (highest+1).ToString() + " constant registers (OK)"); 
     } 
    } 

    static void CheckDirectory(string path) 
    { 
     try 
     { 
      foreach(string file in Directory.GetFiles(path, @"*.xnb")) 
       CheckFile(file); 
      foreach(string dir in Directory.GetDirectories(path)) 
       CheckDirectory(dir); 
     } 
     catch { return; } // Don't care 
    } 

    static int Main(string[] args) 
    { 
     root = args[0]; 

     Form form = new Form(); // Dummy form for creating a graphics device 
     GraphicsDeviceService gds = GraphicsDeviceService.AddRef(form.Handle, 
       form.ClientSize.Width, form.ClientSize.Height); 

     ServiceContainer services = new ServiceContainer(); 
     services.AddService<IGraphicsDeviceService>(gds); 
     content = new ContentManager(services, root); 

     CheckDirectory(root); 

     return retval; 
    } 
}