1

在 HLSL 中,有没有办法限制编译器使用的常量寄存器的数量?

具体来说,如果我有类似的东西:

float4 foobar[300];

在 vs_2_0 顶点着色器中,编译器将愉快地使用超过 256 个常量寄存器生成效果。但是 2.0 顶点着色器只能保证可以访问 256 个常量寄存器,所以当我尝试使用该效果时,它会在运行时以一种模糊且依赖于 GPU 的方式失败。我宁愿让它在编译时失败。

这个问题特别烦人,因为编译器本身在后台分配常量寄存器,在我要求的寄存器之上。我必须检查组件,看看我是否超过了限制。

理想情况下,我想在 HLSL 中执行此操作(我正在使用 XNA 内容管道),但是如果有一个可以传递给编译器的标志,那也会很有趣。

4

1 回答 1

1

基于 Stringer Bell 对 Disassemble 方法的指出,我开发了一个小型的构建后实用程序来解析和检查效果。请注意,这不是很漂亮。它是为 XNA 3.1 设计的,需要XNA WinForms 示例ServiceContainer中的和GraphicsDeviceService类。在命令行上传递内容目录路径,不带斜杠。

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;
    }
}
于 2010-05-20T12:25:00.880 回答