1

HLSL で、コンパイラが使用する定数レジスタの数を制限する方法はありますか?

具体的には、次のようなものがある場合:

float4 foobar[300];

vs_2_0 頂点シェーダーでは、コンパイラーは 256 を超える定数レジスターを使用して効果をうまく生成します。しかし、2.0 頂点シェーダーは 256 個の定数レジスターへのアクセスが保証されているだけなので、エフェクトを使用しようとすると、実行時にあいまいで GPU に依存する方法で失敗します。コンパイル時に失敗した方がいいです。

この問題は、コンパイラ自体が、私が求めているものの上に、舞台裏で定数レジスタを割り当てるため、特に厄介です。アセンブリをチェックして、制限を超えているかどうかを確認する必要があります。

理想的には、これを HLSL で実行したいと考えています (XNA コンテンツ パイプラインを使用しています) が、コンパイラに渡すことができるフラグがあれば、それも興味深いものです。

4

1 に答える 1

1

ストリンガーベルがDisassembleメソッドを指摘していることに基づいて、ビルド後の小さなユーティリティを作成して、効果を解析および確認しました。これはあまりきれいではないことに注意してください。XNA 3.1用に設計されており、XNAWinFormsサンプル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 に答える