P/Invoke vkGetPhysicalDeviceFeatures 访问冲突

P/Invoke vkGetPhysicalDeviceFeatures Access Violation

我正在为 C# 开发 Vulkan 包装器(我相信很多人都是这样),但我在使用 vkGetPhysicalDeviceFeatures 时遇到了一些问题,它也没有 return 数据,或抛出访问冲突

未管理的一面 - 签名:

spec 的签名是这样的:

void vkGetPhysicalDeviceFeatures(
    VkPhysicalDevice                            physicalDevice,
    VkPhysicalDeviceFeatures*                   pFeatures);

VkPhysicalDevice 是一个 handle 对象,定义为:

#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
VK_DEFINE_HANDLE(VkPhysicalDevice)

这只是一个指针,其他使用 IntPtrSafeHandle 包装器的导入也适用于这种形状的对象。

托管端 - DLL 导入:

预期的 DLL 导入(但失败):

[DllImport("vulkan-1.dll", EntryPoint = "vkGetPhysicalDeviceFeatures")]
internal static extern void GetPhysicalDeviceFeatures(PhysicalDeviceHandle physicalDevice, ref IntPtr features);

这与其他有效导入类似。注意:PhysicalDeviceHandle 派生自 SafeHandle 应该编组为 IntPtr,我还有其他导入的此模式有效。以上在调用时引发访问冲突。


平台:


更新

@V。克拉夫琴科

上面的导入没有问题。我的问题实际上是 vkEnumeratePhysicalDevices 调用。

首先我输入错误,正确的输入看起来像:

[DllImport("vulkan-1.dll", EntryPoint = "vkEnumeratePhysicalDevices ")]
internal static extern Result EnumeratePhysicalDevices (InstanceHandle instance, ref physicalDeviceCount, IntPtr[] physicalDevices);

其次,我实际上错误地使用了该功能。您需要调用 vkEnumeratePhysicalDevices 两次。第一次调用获取设备数量,第二次调用填充设备数组。:

IntPtr[] devices = new IntPtr[]();
uint deviceCount = 0;
// populates deviceCount with the number of devices
Vk.EnumeratePhysicalDevices(instanceHandle, ref deviceCount, null);
// populates the devices array with the handle to each device, will only populate up to deviceCount devices
Vk.EnumeratePhysicalDevices(instanceHandle, ref deviceCount, devices);

注意:这在函数文档的 description/valid 用法部分中有概述,我只是在第一次通读时没有正确解释它。

一旦我最终从 EnumeratePhysicalDevices 获得了正确的句柄值,那么我对 GetPhysicalDeviceFeatures 的最终调用就按预期工作了。 GetPhysicalDeviceFeatures 的最终导入如下所示:

[DllImport("vulkan-1.dll", EntryPoint = "vkGetPhysicalDeviceFeatures")]
internal static extern void GetPhysicalDeviceFeatures(PhysicalDeviceHandle physicalDevice, ref VkPhysicalDeviceFeatures features);

注意:名称中带有Handle的任何变量都是SafeHandle.

的子类

您必须 IntPtr,它确实指向一个有效的对象,而不仅仅是 IntPtr。访问冲突意味着 dll 中的代码正在尝试访问内存,您的 IntPtr 指向但不能,因为您的 IntPtr 未指向有效对象。

总的来说,您应该使用预期的变体,但传递指向有效对象的指针。 工作变体正在工作,因为 ref IntPtr 实际上是指向 IntPtr 的指针,而 ref IntPtr 指向的 IntPtr 对象的位置是有效内存。