【发布时间】:2014-08-01 21:58:47
【问题描述】:
我创建了一个自定义结构来处理将被编组到 GPU 的 RGBA 值。
在我的类型中,我将单独的 R、G、B 和 A 组件保存为字节值,并重叠一个 32 位无符号整数 (Uint32) 以轻松传递和分配打包值。我知道这个概念很明显,但这里有一个很好的结构示例:
[StructLayout(LayoutKind.Explicit, Size = 4)]
public struct RGBA
{
[FieldOffset(0)]
public uint32 PackedValue;
[FieldOffset(0)]
public byte R;
[FieldOffset(1)]
public byte G;
[FieldOffset(2)]
public byte B;
[FieldOffset(3)]
public byte A;
}
由于 c# 处理结构的方式,每个字段都必须在定义的任何构造函数中显式分配。就我而言,这意味着由于字段重叠,我必须在任何构造函数中分配两次值。
我可以使用:
public RGBA(uint packed value)
{
R = G = B = A = 0; // initialize all to defaults before assigning packed value
PackedValue = packedValue;
}
public RGBA(byte r, byte g, byte b, byte a)
{
PackedValue = 0; // initialize to default before assigning components
R = r;
G = g;
B = b;
A = a;
}
或者我可以像这样首先在每个构造函数上调用基本构造函数:
public RGBA(uint packedValue) : this()
{
PackedValue = packedValue;
}
public RGBA(byte r, byte g, byte b, byte a) : this()
{
R = r;
G = g;
B = b;
A = a;
}
由于这是用于图形代码,因此性能至关重要,我正在尝试找到在这种情况下处理构建的最佳方法。使用第一个示例似乎是两个示例中开销最小的,因为虽然它涉及分配所有字段两次(一次用于 PackedValue,一次用于 R、G、B 和 A 字段),但另一个示例涉及分配所有值 3 次(两次在默认构造函数中,一次在定义的构造函数中)。
有没有办法让编译器认识到这些字段重叠并且如果 PackedValue 被分配,则不需要明确分配 R、G、B 和 A,反之亦然?我假设这可以通过手动调整生成的 IL 来完成,但我想知道是否有办法直接在 c# 中更优化地处理这个问题。
有什么想法吗?
【问题讨论】:
-
你能使用属性来避免双重初始化吗?例如。
public byte A { get { return (byte)(PackedValue >> 24); } }? -
好问题。 . .您是否尝试过任何基准测试?也许编译器足够聪明,可以忽略一些无用的调用。
-
我想我可以对打包值使用按位操作,这样就不必分配 R、G、B 和 A 字段。 get/set 代码增加的开销是不希望的,但如果编译器不能很好地运行,我可能不得不这样做。不确定它在 GPU 上的行为,但一旦编组
-
您必须对此进行基准测试。尚不清楚 JIT 的作用。 CLR JIT 并不擅长优化东西。查看已开启优化的 Release 模式下的反汇编。
标签: c# memory data-structures constructor