我目前正在为OpenGL编写一个瘦C#绑定。我刚刚实施了OpenGL GenVertexArrays 功能,该功能具有以下特征: OpenGL Documentation on glGenVertexArrays
本质上,您传递一个数组,用于存储由OpenGL创建的顶点数组的生成对象值。
为了创建绑定,我使用委托,因为glGenVertexArrays是一个OpenGL扩展函数,所以我必须使用wglGetProcAddress动态加载它。我在C#中定义的委托签名如下所示:
[SuppressUnmanagedCodeSecurity]
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void glGenVertexArrays(uint amount, uint[] array);
使用Marshal.GetDelegateForFunctionPointer检索函数指针并将其转换为此委托,如下所示:
IntPtr proc = wglGetProcAddress(name);
del = Marshal.GetDelegateForFunctionPointer(proc, delegateType);
无论如何,这是困扰我的:
在任何官方文档中,我可以找到参考类型(包括数组)的默认编组行为,是这样的:
默认情况下,引用类型(类,数组,字符串和接口) 按值传递的值将作为“性能参数”进行封送处理 原因。除非您申请,否则您不会看到对这些类型的更改 InAttribute和OutAttribute(或只是OutAttribute)到方法 参数。
这取自此MSDN页面:MSDN page on directional attributes
但是,从我的委托签名可以看出,[In]和[Out]方向属性尚未用于无符号整数数组,这意味着当我调用此函数时,我实际上应该看不到生成的对象值,OpenGL应该存储在其中。除此之外,我是。使用此签名,运行调试器时可以得到以下结果:
可以看出,即使我没有明确使用[Out]属性,调用绝对会影响数组。根据我的理解,这不是我应该期待的结果。
有谁知道这背后的原因?我知道这似乎是一个小问题,但我很好奇,为什么这似乎打破了微软描述的默认编组行为。与纯平台调用原型相比,在调用委托时是否会有一些幕后的事情发生?或者我误解了文档?
[编辑]
对于任何好奇的人来说,调用委托的公共方法是在静态" GL"上定义的。类,并如下:
public static void GenVertexArrays(uint amount, uint[] array)
{
InvokeExtensionFunction<glGenVertexArrays>()(amount, array);
}
答案 0 :(得分:2)
在你链接的文档页面上没有提到它,但有another topic专用于数组的编组,它说:
使用固定优化时,在与同一公寓中的对象进行交互时,blittable数组可能会显示为In / Out参数。
在你的情况下满足这两个条件:uint数组是blittable,并且没有机器到机器的编组。声明它[Out]仍然是一个好主意,所以你的意图记录在代码中。
答案 1 :(得分:1)
在一般情况下,文档是正确的。但uint
有点特殊,它是 blittable 类型。一个昂贵的词意味着pinvoke marshaller不必做任何特殊的转换数组元素值。 C#中的uint与C中的unsigned int完全相同。根本不是巧合,它是处理器本身可以处理的那种类型。
因此,编组器可以简单地固定数组并将指针传递给第一个数组元素作为第二个参数。非常快,总是你想要的。并且该函数直接写入托管数组,因此不需要复制值。有点危险,你永远不想对amount
论证撒谎,GC堆腐败是一个过于丑陋的错误诊断。
大多数简单值类型和简单值类型的结构都是blittable。 bool
是一个值得注意的例外。即使没有必要,您也不必为使用[Out]而感到抱歉。编组人员在此忽略了它。