我有 <job id="compositeJdbcReaderJob" xmlns="http://www.springframework.org/schema/batch">
<step id="compositeJdbcReaderStep" next="compositeJdbcReaderStep2">
<tasklet>
<chunk reader="itemReader1" writer="itemWriter" commit-interval="5" />
</tasklet>
</step>
<step id="compositeJdbcReaderStep2">
<tasklet>
<chunk reader="itemReader2" writer="itemWriter2" commit-interval="5" />
</tasklet>
</step>
</job>
种颜色需要通过byte[]
转移到Texture2D
对象。
我想知道从SetPixels(Color32[])
创建Color32[]
的最快方法是什么。
由于每个byte[]
是4个字节(每个通道1个字节),因此将有四分之一的元素。
Color32
不允许使用不同的对象数组类型。
根据我的阅读,似乎托管代码无法将Array.CopyTo
重新解释为byte[]
并完全跳过该副本。
与此相反(Color32[]
- &gt; Color32[]
)has a SO solution通过编组,但似乎涉及大量复制。
byte[]
就我而言,我正在使用:
private static byte[] Color32ArrayToByteArray(Color32[] colors)
{
int length = 4 * colors.Length;
byte[] bytes = new byte[length];
IntPtr ptr = Marshal.AllocHGlobal(length); // unmanaged memory alloc
Marshal.StructureToPtr(colors, ptr, true); // memcpy 1
Marshal.Copy(ptr, bytes, 0, length); // memcpy 2
Marshal.FreeHGlobal(ptr);
return bytes;
}
但是,在执行 int length = bytes.Length;
IntPtr ptr = Marshal.AllocHGlobal(length); // unmanaged mem alloc
Marshal.Copy(bytes, 0, ptr, length); // memcpy 1
Marshal.PtrToStructure(ptr, colors); // memcpy 2
Marshal.FreeHGlobal(ptr);
后,我看不到纹理更新。还在试图找出原因。
无论如何,我必须做2份内存副本才能在C#中实现这一目标吗?好像这样浪费.. 我正在寻找C#中的工会来绕过这些副本。
答案 0 :(得分:2)
这是我学到的东西:
1)没有必要使用b / w托管和非托管内存来将byte []转换为Color32 [],反之亦然。相反,在C#中使用联合:
[StructLayout(LayoutKind.Explicit)]
public struct Color32Bytes
{
[FieldOffset(0)]
public byte[] byteArray;
[FieldOffset(0)]
public Color32[] colors;
}
Color32Bytes data = new Color32Bytes();
data.byteArray = new byte[width * height * bytesPerPixel];
data.colors = new Color32[width * height];
现在,如果您使用来自相机的数据更新byteArray,您可以使用Texture2D
将其应用于myTexture.SetPixels(data.colors)
;
不涉及复制。
2)不需要上面的联合解决方案。哈哈。
正如NineBerry指出的那样,您只需将原始字节缓冲区上传到纹理通道即可
myTexture.LoadRawTextureData(bytes);
这在我的情况下是完美的,因为我的相机字节缓冲来自BGRA(从低到高)并且我需要在上传之前调整频道(昂贵)或者如果我去的那样在我的着色器中解决它(1)< / p>
3)Unity中的SetPixels
方法在低端系统上可能很昂贵。我没有深入挖掘,但我怀疑这是因为在引擎盖下创建的D3D纹理使用D3D_USAGE_DEFAULT,这意味着更新它们必须使用UpdateSubresource,这会导致驱动程序副本和可能的停顿(不能更新GPU当前使用的资源。
因此,理想的解决方案是编写一个本机插件,使用D3D_USAGE_DYNAMIC创建2D纹理,map-updates-unmaps,并将该引用传递回Unity。现在有点矫枉过正,但我稍后可能会再次访问。