public static VkDevice Create(Settings settings, VkPhysicalDeviceFeatures enabledFeatures, CStringList enabledExtensions, VkQueueFlags requestedQueueTypes = VkQueueFlags.Graphics | VkQueueFlags.Compute | VkQueueFlags.Transfer) { instanceExtensions.Add(Vulkan.KHRSurfaceExtensionName); instanceExtensions.Add(Vulkan.KHRGetPhysicalDeviceProperties2ExtensionName); enabledExtensions.Add(Vulkan.KHRMaintenance1ExtensionName); enabledExtensions.Add(Vulkan.EXTInlineUniformBlockExtensionName); //enabledExtensions.Add(Strings.VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT); CreateInstance(settings); // Physical Device var physicalDevices = Vulkan.vkEnumeratePhysicalDevices(VkInstance); // TODO: Implement arg parsing, etc. int selectedDevice = 0; PhysicalDevice = physicalDevices[selectedDevice]; Debug.Assert(PhysicalDevice.Handle != IntPtr.Zero); vkGetPhysicalDeviceProperties(PhysicalDevice, out VkPhysicalDeviceProperties properties); Properties = properties; vkGetPhysicalDeviceFeatures(PhysicalDevice, out VkPhysicalDeviceFeatures features); Features = features; if (features.tessellationShader) { enabledFeatures.tessellationShader = true; } if (features.multiDrawIndirect) { enabledFeatures.multiDrawIndirect = true; } // Enable anisotropic filtering if supported if (features.samplerAnisotropy) { enabledFeatures.samplerAnisotropy = true; } // Enable texture compression if (features.textureCompressionBC) { enabledFeatures.textureCompressionBC = true; } else if (features.textureCompressionASTC_LDR) { enabledFeatures.textureCompressionASTC_LDR = true; } else if (features.textureCompressionETC2) { enabledFeatures.textureCompressionETC2 = true; } if (features.sparseBinding && features.sparseResidencyImage2D) { enabledFeatures.shaderResourceResidency = true; enabledFeatures.shaderResourceMinLod = true; enabledFeatures.sparseBinding = true; enabledFeatures.sparseResidencyImage2D = true; } else { Log.Warn("Sparse binding not supported"); } // Memory properties are used regularly for creating all kinds of buffers VkPhysicalDeviceMemoryProperties memoryProperties; vkGetPhysicalDeviceMemoryProperties(PhysicalDevice, out memoryProperties); MemoryProperties = memoryProperties; var qf = Vulkan.vkGetPhysicalDeviceQueueFamilyProperties(PhysicalDevice); QueueFamilyProperties.Add(qf); var extensions = Vulkan.vkEnumerateDeviceExtensionProperties(PhysicalDevice); foreach (var ext in extensions) { string strExt = UTF8String.FromPointer(ext.extensionName); //enabledExtensions.Add((IntPtr)ext.extensionName); supportedExtensions.Add(strExt); } device = CreateLogicalDevice(Features, enabledExtensions, true, requestedQueueTypes); if (device != VkDevice.Null) { VkPipelineCacheCreateInfo pipelineCacheCreateInfo = new VkPipelineCacheCreateInfo() { sType = VkStructureType.PipelineCacheCreateInfo }; VulkanUtil.CheckResult(vkCreatePipelineCache(device, &pipelineCacheCreateInfo, null, out pipelineCache)); } return(device); }
public unsafe Swapchain(IntPtr sdlWindow) { SDL_version version; SDL_GetVersion(&version); SDL_SysWMinfo sysWmInfo; sysWmInfo.version = version; int result = SDL_GetWMWindowInfo(sdlWindow, &sysWmInfo); if (result == 0) { throw new InvalidOperationException("Couldn't retrieve SDL window info."); } VkSurfaceKHR surface; if (SDL_Vulkan_CreateSurface(sdlWindow, Device.VkInstance.Handle, (IntPtr)(&surface)) == 0) { var error = UTF8String.FromPointer(SDL_GetError()); Log.Error("create surface failed." + error); } ; Surface = surface; VkResult err; /* * if (sysWmInfo.subsystem == SysWMType.Windows) * { * Win32WindowInfo win32Info = Unsafe.Read<Win32WindowInfo>(&sysWmInfo.info); * // Create the os-specific Surface * VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = VkWin32SurfaceCreateInfoKHR.New(); * var processHandle = Process.GetCurrentProcess().SafeHandle.DangerousGetHandle(); * surfaceCreateInfo.hinstance = processHandle; * surfaceCreateInfo.hwnd = win32Info.Sdl2Window; * err = vkCreateWin32SurfaceKHR(Device.VkInstance, &surfaceCreateInfo, null, &surface); * Surface = surface; * } * else if (sysWmInfo.subsystem == SysWMType.X11) * { * X11WindowInfo x11Info = Unsafe.Read<X11WindowInfo>(&sysWmInfo.info); * VkXlibSurfaceCreateInfoKHR surfaceCreateInfo = VkXlibSurfaceCreateInfoKHR.New(); * surfaceCreateInfo.dpy = (Vulkan.Xlib.Display*)x11Info.display; * surfaceCreateInfo.window = new Vulkan.Xlib.Window { Value = x11Info.Sdl2Window }; * err = vkCreateXlibSurfaceKHR(Device.VkInstance, &surfaceCreateInfo, null, out surface); * Surface = surface; * } * else * { * throw new NotImplementedException($"SDL backend not implemented: {sysWmInfo.subsystem}."); * }*/ var queueProps = vkGetPhysicalDeviceQueueFamilyProperties(Device.PhysicalDevice); // Iterate over each queue to learn whether it supports presenting: // Find a queue with present support // Will be used to present the swap chain Images to the windowing system VkBool32 *supportsPresent = stackalloc VkBool32[(int)queueProps.Length]; for (int i = 0; i < queueProps.Length; i++) { vkGetPhysicalDeviceSurfaceSupportKHR(Device.PhysicalDevice, (uint)i, Surface, out supportsPresent[i]); } // Search for a graphics and a present queue in the array of queue // families, try to find one that supports both uint graphicsQueueNodeIndex = uint.MaxValue; uint presentQueueNodeIndex = uint.MaxValue; for (int i = 0; i < queueProps.Length; i++) { if ((queueProps[i].queueFlags & VkQueueFlags.Graphics) != 0) { if (graphicsQueueNodeIndex == uint.MaxValue) { graphicsQueueNodeIndex = (uint)i; } if (supportsPresent[i] == true) { graphicsQueueNodeIndex = (uint)i; presentQueueNodeIndex = (uint)i; break; } } } if (presentQueueNodeIndex == uint.MaxValue) { // If there's no queue that supports both present and graphics // try to find a separate present queue for (uint i = 0; i < queueProps.Length; ++i) { if (supportsPresent[i] == true) { presentQueueNodeIndex = i; break; } } } // Exit if either a graphics or a presenting queue hasn't been found if (graphicsQueueNodeIndex == uint.MaxValue || presentQueueNodeIndex == uint.MaxValue) { throw new InvalidOperationException("Could not find a graphics and/or presenting queue!"); } // todo : Add support for separate graphics and presenting queue if (graphicsQueueNodeIndex != presentQueueNodeIndex) { throw new InvalidOperationException("Separate graphics and presenting queues are not supported yet!"); } QueueNodeIndex = graphicsQueueNodeIndex; // Get list of supported Surface formats uint formatCount; err = vkGetPhysicalDeviceSurfaceFormatsKHR(Device.PhysicalDevice, Surface, &formatCount, null); Debug.Assert(err == VkResult.Success); Debug.Assert(formatCount > 0); using Vector <VkSurfaceFormatKHR> surfaceFormats = new Vector <VkSurfaceFormatKHR>(formatCount); err = vkGetPhysicalDeviceSurfaceFormatsKHR(Device.PhysicalDevice, Surface, &formatCount, surfaceFormats.DataPtr); surfaceFormats.Count = formatCount; Debug.Assert(err == VkResult.Success); // If the Surface format list only includes one entry with VK_FORMAT_UNDEFINED, // there is no preferered format, so we assume VK_FORMAT_B8G8R8A8_UNORM if ((formatCount == 1) && (surfaceFormats[0].format == VkFormat.Undefined)) { ColorFormat = VkFormat.B8G8R8A8UNorm; ColorSpace = surfaceFormats[0].colorSpace; } else { // iterate over the list of available Surface format and // check for the presence of VK_FORMAT_B8G8R8A8_UNORM bool found_B8G8R8A8_UNORM = false; foreach (var surfaceFormat in surfaceFormats) { if (surfaceFormat.format == VkFormat.B8G8R8A8UNorm) { ColorFormat = surfaceFormat.format; ColorSpace = surfaceFormat.colorSpace; found_B8G8R8A8_UNORM = true; break; } } // in case VK_FORMAT_B8G8R8A8_UNORM is not available // select the first available color format if (!found_B8G8R8A8_UNORM) { ColorFormat = surfaceFormats[0].format; ColorSpace = surfaceFormats[0].colorSpace; } } }