在HLSL中,有没有办法限制编译器使用的常量寄存器的数量?
具体来说,如果我有类似的东西:
float4 foobar[300];
在vs_2_0顶点着色器中,编译器将使用超过256个常量寄存器快速生成效果。但是2.0顶点着色器只能保证能够访问256个常量寄存器,因此当我尝试使用该效果时,它会在运行时以一种模糊且依赖于GPU的方式失败。我宁愿在编译时失败。
这个问题特别烦人,因为编译器本身在我要求的场景之后在幕后分配常量寄存器。我必须检查装配,看看我是否超过限制。
理想情况下,我想在HLSL中执行此操作(我正在使用XNA内容管道),但是如果有一个可以传递给编译器的标志也很有趣。
答案 0 :(得分:1)
基于Stringer Bell指出Disassemble方法,我已经启动了一个小的post-build实用程序来解析并检查效果。请注意,这不是很漂亮。它专为XNA 3.1设计,需要the XNA WinForms sample中的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;
}
}