HLSL:在编译时强制执行常量寄存器限制 [英] HLSL: Enforce Constant Register Limit at Compile Time

查看:223
本文介绍了HLSL:在编译时强制执行常量寄存器限制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In HLSL, is there any way to limit the number of constant registers that the compiler uses?

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

Specifically, if I have something like:

float4 foobar[300];

在vs_2_0顶点着色器中,编译器将使用超过256个常量寄存器来轻松生成效果.但是,仅保证2.0顶点着色器可以访问256个常量寄存器,因此当我尝试使用该效果时,它在运行时会以晦涩且依赖于GPU的方式失败.我宁愿让它在编译时失败.

In a vs_2_0 vertex shader, the compiler will merrily generate the effect with more than 256 constant registers. But a 2.0 vertex shader is only guaranteed to have access to 256 constant registers, so when I try to use the effect, it fails in an obscure and GPU-dependent way at runtime. I would much rather have it fail at compile time.

这个问题尤其令人讨厌,因为编译器本身在幕后在我要的寄存器之后分配常量寄存器.我必须检查程序集以查看是否超出限制.

This problem is especially annoying as the compiler itself allocates constant registers behind the scenes, on top of the ones I am asking for. I have to check the assembly to see if I'm over the limit.

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

Ideally I'd like to do this in HLSL (I'm using the XNA content pipeline), but if there's a flag that can be passed to the compiler that would also be interesting.

推荐答案

基于Stringer Bell指出的Disassemble方法,我制作了一个小型的post-build实用程序来分析和检查效果.请注意,这不是很漂亮.它是为XNA 3.1设计的,需要 XNA中的ServiceContainerGraphicsDeviceService类. WinForms示例.在命令行上传递内容目录路径,且不带斜杠.

Based on Stringer Bell's pointing out of the Disassemble method, I have whipped up a small post-build utility to parse and check the effect. Be warned that this is not very pretty. It is designed for XNA 3.1 and requires the ServiceContainer and GraphicsDeviceService classes from the XNA WinForms sample. Pass a content directory path on the command line with no trailing slash.

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;
    }
}

这篇关于HLSL:在编译时强制执行常量寄存器限制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆