2016-02-22 4 views
1

У меня есть острая идея написать обертку для Vulkan в C#. К сожалению, второй вызов API Vulkan уже невозможен. ниже код взят из примеров Sascha Вулкана WILLEMS' и преобразуется в C# код:AccessViolationException при вызове vkEnumeratePhysicalDevices через pInvoke из C#

Vk.ApplicationInfo applicationInfo = new Vk.ApplicationInfo(); 
applicationInfo.sType = Vk.StructureType.STRUCTURE_TYPE_APPLICATION_INFO; 
applicationInfo.pApplicationName = "Example"; 
applicationInfo.pEngineName = "Example"; 
applicationInfo.apiVersion = (uint)Math.Pow(2, 22) + 2; 

string[] enabledExtensions = new string[] { "VK_KHR_surface", "VK_KHR_win32_surface" }; 

Vk.InstanceCreateInfo instanceCreateInfo = new Vk.InstanceCreateInfo(); 
instanceCreateInfo.sType = Vk.StructureType.STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 
instanceCreateInfo.pNext = null; 
instanceCreateInfo.pApplicationInfo = applicationInfo; 

instanceCreateInfo.enabledExtensionCount = (uint)enabledExtensions.Count(); 
instanceCreateInfo.ppEnabledExtensionNames = enabledExtensions; 


Vk.Instance theInstance = new Vk.Instance(); 
Vk.Result vr = Vk.vkCreateInstance(instanceCreateInfo, IntPtr.Zero, theInstance); 
// vr = SUCCESS 

uint gpuCount = 0; 
vr = Vk.vkEnumeratePhysicalDevices(theInstance, ref gpuCount, IntPtr.Zero); 
//Fails with System.AccessViolationException 

с

public static class Vk 
{ 

    public enum Result 
    { 
     SUCCESS = 0, 
     ... 
    }; 


    public enum StructureType 
    { 
     ... 
    } 

    static Vk() 
    { 
     List<string> path = new List<string>() { @"C:\VulkanSDK\1.0.3.1\Source\lib32\" }; 
     AddEnvironmentPaths(path); 
    } 

    static void AddEnvironmentPaths(IEnumerable<string> paths) 
    { 
     var path = new[] { Environment.GetEnvironmentVariable("PATH") ?? string.Empty }; 

     string newPath = string.Join(Path.PathSeparator.ToString(), path.Concat(paths)); 

     Environment.SetEnvironmentVariable("PATH", newPath); 
    } 


    [DllImport("vulkan-1.dll")] 
    public static extern Result vkCreateInstance(InstanceCreateInfo instanceCreateInfo, IntPtr pAllocator, Instance instance); 

    [StructLayout(LayoutKind.Sequential)] 
    public class InstanceCreateInfo 
    { 
     public StructureType sType; 
     public object pNext; 
     public uint flags; 
     public ApplicationInfo pApplicationInfo; 
     public uint enabledLayerCount; 
     public string[] ppEnabledLayerNames; 
     public uint enabledExtensionCount; 
     public string[] ppEnabledExtensionNames; 
    } 



    [StructLayout(LayoutKind.Sequential)] 
    public class ApplicationInfo 
    { 
     public StructureType sType; 
     public object pNext; 
     public string pApplicationName; 
     public uint applicationVersion; 
     public string pEngineName; 
     public uint engineVersion; 
     public uint apiVersion; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public class Instance 
    { 
    } 

    [DllImport("vulkan-1.dll")] 
    public static extern Result vkEnumeratePhysicalDevices(Instance instance, ref uint pPhysicalDeviceCount, PhysicalDevice pPhysicalDevices); 

    [DllImport("vulkan-1.dll")] 
    public static extern Result vkEnumeratePhysicalDevices(Instance instance, ref uint pPhysicalDeviceCount, IntPtr pPhysicalDevices); 



    public class PhysicalDevice 
    { 
    } 
} 

Моего Подозрения в том, что Vk.Instance должно быть что-то другое, чем просто пустой класс. VkInstance находится в официальном vulkan.h, определяемом как typedef struct VkInstance_T* VkInstance. К сожалению, мое понимание этой линии очень ограничено. Я уже пробовал обменивать тип Vk.Instance с IntPtr и object, но безуспешно.

Тезисы важные сегменты из vulkan.h

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

VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
    const VkInstanceCreateInfo* pCreateInfo, 
    const VkAllocationCallbacks* pAllocator, 
    VkInstance* pInstance); 

VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(
    VkInstance instance, 
    uint32_t* pPhysicalDeviceCount, 
    VkPhysicalDevice* pPhysicalDevices); 
+0

Возможно, вы используете 'IntPtr' для' theInstance'. Насколько я понимаю, ответственность за их создание лежит в 'vkCreateInstance'. –

+0

Все, что указатель в C API, вероятно, должно быть IntPtr в ваших подписях PInvoke, а затем использовать методы Marshal.xxx() для их чтения/записи. Вы также можете уйти с небезопасными блоками и указателями структуры в них (обратите внимание: вам обычно требуется структура, а не класс, для C-структур (из-за vtables и т. П.)). Кроме того, VkInstance и VkPhysicalDevice уже являются указателями, поэтому последние аргументы являются указателями на указатели; для CreateInstance "out IntPtr pInstance", вероятно, будет работать; fir enum, вы, скорее всего, захотите маршалировать count + ptr как массив. – Zastai

+0

Вообще говоря, гораздо более желательно смотреть на использование чего-то вроде swig для создания базового слоя взаимодействия, а затем, возможно, добавить вокруг него некоторую модель OO. – Zastai

ответ

0

Zastai ответил на мой вопрос. Это должно было быть

[DllImport("vulkan-1.dll")] 
public static extern Result vkCreateInstance(InstanceCreateInfo instanceCreateInfo, IntPtr pAllocator, out IntPtr instance); 

, потому что это действительно были указатели на указатели.

IntPtr instance; 
Vk.Result vr = Vk.vkCreateInstance(instanceCreateInfo, IntPtr.Zero, out instance); 
uint gpuCount = 0; 
vr = Vk.vkEnumeratePhysicalDevices(instance, ref gpuCount, IntPtr.Zero); 

Большое спасибо!

Смежные вопросы