HLSL: принудительно использовать ограничение регистра констант во время компиляции - PullRequest
1 голос
/ 19 мая 2010

В HLSL, есть ли способ ограничить количество константных регистров, которые использует компилятор?

В частности, если у меня есть что-то вроде:

float4 foobar[300];

В вершинном шейдере vs_2_0 компилятор с удовольствием сгенерирует эффект, используя более 256 константных регистров. Но вершинный шейдер 2.0 гарантированно будет иметь доступ только к 256 константным регистрам, поэтому, когда я пытаюсь использовать эффект, во время выполнения он дает сбой неясным и зависимым от GPU способом. Я бы предпочел, чтобы он потерпел неудачу во время компиляции.

Эта проблема особенно раздражает, поскольку сам компилятор выделяет постоянные регистры за кулисами, помимо тех, которые я запрашиваю. Я должен проверить сборку, чтобы увидеть, не превышаю ли я предел.

В идеале я хотел бы сделать это в HLSL (я использую конвейер содержимого XNA), но если есть флаг, который можно передать компилятору, который также будет интересен.

1 Ответ

1 голос
/ 20 мая 2010

Основываясь на указании Стрингера Белла на метод Disassemble, я выбрал небольшую утилиту после сборки для анализа и проверки эффекта. Имейте в виду, что это не очень красиво. Он разработан для XNA 3.1 и требует классов ServiceContainer и GraphicsDeviceService из образца XNA WinForms . Передайте путь к каталогу содержимого в командной строке без косой черты.

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