代码之家  ›  专栏  ›  技术社区  ›  Andrew Russell

hlsl:在编译时强制执行常量寄存器限制

  •  1
  • Andrew Russell  · 技术社区  · 15 年前

    在HLSL中,有没有什么方法可以限制编译器使用的常量寄存器的数量?

    具体来说,如果我有这样的东西:

    float4 foobar[300];
    

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

    这个问题特别令人恼火,因为编译器本身在后台,在我要求的寄存器之上,分配常量寄存器。我得检查一下总成,看我是否超过极限。

    理想情况下,我希望在HLSL中这样做(我使用的是XNA内容管道),但是如果有一个标志可以传递给编译器,那么这个标志也会很有趣。

    1 回复  |  直到 15 年前
        1
  •  1
  •   Andrew Russell    15 年前

    基于StringerBell对反汇编方法的指出,我创建了一个小的后期构建工具来解析和检查效果。请注意,这不是很漂亮。它是为XNA 3.1设计的,需要 ServiceContainer GraphicsDeviceService 类来自 the XNA WinForms sample . 在命令行上传递一个不带尾随斜杠的内容目录路径。

    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;
        }
    }
    
    推荐文章