예제 #1
0
 public static long CreateWindowSurface(Vk.Instance inst, IntPtr window)
 {
     Vk.Result res = (Vk.Result)_glfwCreateWindowSurface(inst.Handle, window, IntPtr.Zero, out IntPtr surface);
     if (res != Vk.Result.Success)
     {
         throw new Vk.VulkanException(res, "Could not create Vulkan surface from GLFW.");
     }
     return(surface.ToInt64());
 }
        // Destroys the global vulkan objects
        private void destroyGlobalVulkanObjects(Vk.Instance inst, VkExt.DebugReportCallbackExt debugReport, Vk.Device device)
        {
            device?.Dispose();
            LINFO("Destroyed Vulkan device.");

            if (debugReport != null)
            {
                debugReport.Dispose();
                LINFO("Destroyed Vulkan debug report callback.");
            }

            inst.Dispose();
            LINFO("Destroyed Vulkan instance.");
        }
예제 #3
0
        internal Instance(string appName, string engName,
                          VER appVer, VER engVer, VER apiVer, bool bDebug)
        {
            string vlName = "";

            if (bDebug)
            {
                if (!bCheckValidation(out vlName))
                {
                    return;
                }
            }

            ApplicationInfo ai = new ApplicationInfo();

            ai.ApplicationName    = appName;
            ai.ApplicationVersion = appVer;
            ai.EngineName         = engName;
            ai.EngineVersion      = engVer;
            ai.ApiVersion         = apiVer;

            InstanceCreateInfo ici = new InstanceCreateInfo();

            ici.Next            = IntPtr.Zero;
            ici.ApplicationInfo = ai;

            List <string> extensions = new List <string>();

            extensions.AddRange(Vulkan.GetRequiredInstanceExtensions());
            if (bDebug)
            {
                extensions.Add(Constant.InstanceExtension.ExtDebugReport);
            }

            //get extension stuff from glfw
            ici.EnabledExtensionNames = extensions.ToArray();

            if (bDebug)
            {
                ici.EnabledLayerNames = new string[1] {
                    vlName
                };
            }

            mInstance = new INST(ici, null);
        }
예제 #4
0
        bool bCheckValidation(out string vlName)
        {
            LayerProperties [] lps = INST.EnumerateLayerProperties();

            bool bFound = false;

            vlName = "";
            foreach (LayerProperties lp in lps)
            {
                if (lp.Description.Contains("Standard Validation"))
                {
                    bFound = true;
                    vlName = lp.LayerName;
                }
            }

            if (!bFound)
            {
                Console.WriteLine("Missing standard validation layer...");
                return(false);
            }
            return(true);
        }
        // Creates a VkInstance
        private void createVulkanInstance(out Vk.Instance instance, out VkExt.DebugReportCallbackExt debugReport)
        {
            var appVersion = Application.AppParameters.Version;
            var engVersion = Assembly.GetExecutingAssembly().GetName().Version;

            // Build the app info
            Vk.ApplicationInfo aInfo = new Vk.ApplicationInfo(
                Application.AppParameters.Name,
                appVersion.ToVkVersion(),
                "Spectrum",
                new Vk.Version(engVersion.Major, engVersion.Minor, engVersion.Revision),
                new Vk.Version(1, 0, 0)
                );

            // Get available instance extensions, and ensure the required ones are present
            var           availExt = Vk.Instance.EnumerateExtensionProperties().Select(ext => ext.ExtensionName).ToArray();
            List <string> reqExt   = new List <string>();

            reqExt.Add(Vk.Constant.InstanceExtension.KhrSurface);
            switch (Platform.OS)
            {
            case PlatformOS.Windows: reqExt.Add(Vk.Constant.InstanceExtension.KhrWin32Surface); break;

            case PlatformOS.Linux: reqExt.Add(Vk.Constant.InstanceExtension.KhrXlibSurface); break;

            case PlatformOS.OSX: reqExt.Add(Vk.Constant.InstanceExtension.MvkMacOSSurface); break;
            }
            {
                var missingExts = reqExt.FindAll(extName => !availExt.Contains(extName));
                if (missingExts.Count > 0)
                {
                    string msg = $"Required Vulkan extensions are missing: {String.Join(", ", missingExts)}";
                    LFATAL(msg);
                    throw new PlatformNotSupportedException(msg);
                }
            }

            // Check for validation layers, if requested
            bool hasDebug = false;

            if (Application.AppParameters.EnableValidationLayers)
            {
                if (availExt.Contains(Vk.Constant.InstanceExtension.ExtDebugReport))
                {
                    var availLay = Vk.Instance.EnumerateLayerProperties().Select(layer => layer.LayerName).ToArray();

                    hasDebug = availLay.Contains("VK_LAYER_KHRONOS_validation");
                    if (hasDebug)
                    {
                        reqExt.Add(Vk.Constant.InstanceExtension.ExtDebugReport);
                    }
                    else
                    {
                        LERROR("Application requested Vulkan validation layers, but the standard layers are not available.");
                    }
                }
                else
                {
                    LERROR("Application requested Vulkan validation layers, but the debug report extension is not available.");
                }
            }

            // Create the instance
            Vk.InstanceCreateInfo iInfo = new Vk.InstanceCreateInfo(
                aInfo,
                hasDebug ? new[] { "VK_LAYER_KHRONOS_validation" } : null,
                reqExt.ToArray(),
                IntPtr.Zero
                );
            instance = new Vk.Instance(iInfo, null);
            LINFO("Created Vulkan instance.");

            // Create the debug callback if needed
            debugReport = null;
            if (hasDebug)
            {
                VkExt.DebugReportCallbackCreateInfoExt dbInfo = new VkExt.DebugReportCallbackCreateInfoExt(
                    (VkExt.DebugReportFlagsExt.PerformanceWarning | VkExt.DebugReportFlagsExt.Warning | VkExt.DebugReportFlagsExt.Error),
                    _DebugReportCallback,
                    IntPtr.Zero
                    );
                debugReport = VkExt.InstanceExtensions.CreateDebugReportCallbackExt(instance, dbInfo, null);
                LINFO("Created Vulkan debug report callback.");
            }
        }
        // Selects and opens the device
        private void openVulkanDevice(Vk.Instance instance, out Vk.PhysicalDevice pDevice, out Vk.Device lDevice,
                                      out DeviceFeatures features, out DeviceLimits limits, out DeviceInfo info, out DeviceQueues queues,
                                      out Vk.PhysicalDeviceMemoryProperties memory)
        {
            // Enumerate the physical devices, and score and sort them, then remove invalid ones
            var devices = instance.EnumeratePhysicalDevices()
                          .Select(dev => {
                var score = scoreDevice(dev,
                                        out Vk.PhysicalDeviceProperties props,
                                        out Vk.PhysicalDeviceFeatures feats,
                                        out Vk.PhysicalDeviceMemoryProperties memProps,
                                        out Vk.QueueFamilyProperties[] qfams);
                return(device: dev, props, feats, memProps, queues: qfams, score);
            })
                          .OrderByDescending(dev => dev.score)
                          .ToList();

            devices.RemoveAll(dev => {
                if (dev.score == 0)
                {
                    LDEBUG($"Ignoring invalid physical device: {dev.props.DeviceName}.");
                    return(true);
                }
                return(false);
            });
            if (devices.Count == 0)
            {
                throw new PlatformNotSupportedException("This system does not have any valid physical devices.");
            }
            var bestDev = devices[0];

            // Ensure extension support
            var aExts = bestDev.device.EnumerateExtensionProperties().Select(ext => ext.ExtensionName).ToArray();
            var rExts = new List <string> {
                Vk.Constant.DeviceExtension.KhrSwapchain
            };

            {
                var missing = rExts.FindAll(ext => !aExts.Contains(ext));
                if (missing.Count > 0)
                {
                    string msg = $"Required Vulkan device extensions are missing: {String.Join(", ", missing)}";
                    LFATAL(msg);
                    throw new PlatformNotSupportedException(msg);
                }
            }

            // Prepare the queue families (we need to ensure a single queue for graphics and present)
            // In the future, we will operate with a separate transfer queue, if possible, as well as a separate compute queue
            Vk.DeviceQueueCreateInfo[] qInfos;
            bool sepTrans = false;             // If there is a separate transfer queue

            {
                var qfams = bestDev.queues
                            .Select((queue, idx) => (queue, present: Glfw.GetPhysicalDevicePresentationSupport(instance, bestDev.device, (uint)idx), family: idx))
                            .ToArray();
                var gFam = qfams.FirstOrDefault(fam => (fam.queue.QueueFlags & Vk.Queues.Graphics) > 0 && fam.present);
                if (gFam.queue.QueueCount == 0 && gFam.family == 0)
                {
                    throw new PlatformNotSupportedException("The selected device does not support a graphics queue with present capabilities.");
                }
                sepTrans = gFam.queue.QueueCount > 1;
                qInfos   = new Vk.DeviceQueueCreateInfo[] {
                    new Vk.DeviceQueueCreateInfo(gFam.family, sepTrans ? 2 : 1, new[] { 1.0f, 0.5f })
                };
            }

            // Populate the limits
            limits = default;
            limits.MaxTextureSize1D = (uint)bestDev.props.Limits.MaxImageDimension1D;
            limits.MaxTextureSize2D = (uint)bestDev.props.Limits.MaxImageDimension2D;
            limits.MaxTextureSize3D = (uint)bestDev.props.Limits.MaxImageDimension3D;
            limits.MaxTextureLayers = (uint)bestDev.props.Limits.MaxImageArrayLayers;

            // Populate the features
            features = default;
            Vk.PhysicalDeviceFeatures enFeats = default;
            var rFeats = Application.AppParameters.EnabledGraphicsFeatures;
            var strict = Application.AppParameters.StrictGraphicsFeatures;

            bool _enableFeature(bool avail, string name)
            {
                if (!avail)
                {
                    if (strict)
                    {
                        throw new PlatformNotSupportedException($"The required device feature '{name}' is not available.");
                    }
                    else
                    {
                        LERROR($"The requested device feature '{name}' is not available.");
                    }
                    return(false);
                }
                return(true);
            }

            if (rFeats.FillModeNonSolid)
            {
                enFeats.FillModeNonSolid = features.FillModeNonSolid = _enableFeature(bestDev.feats.FillModeNonSolid, "FillModeNonSolid");
            }
            if (rFeats.WideLines)
            {
                enFeats.WideLines = features.WideLines = _enableFeature(bestDev.feats.WideLines, "WideLines");
            }
            if (rFeats.DepthClamp)
            {
                enFeats.DepthClamp = features.DepthClamp = _enableFeature(bestDev.feats.DepthClamp, "DepthClamp");
            }
            if (rFeats.AnisotropicFiltering)
            {
                enFeats.SamplerAnisotropy = features.AnisotropicFiltering = _enableFeature(bestDev.feats.SamplerAnisotropy, "AnisotropicFiltering");
            }

            // Create the device
            Vk.DeviceCreateInfo dInfo = new Vk.DeviceCreateInfo(
                qInfos,
                rExts.ToArray(),
                enFeats,
                IntPtr.Zero
                );
            pDevice = bestDev.device;
            lDevice = pDevice.CreateDevice(dInfo, null);
            LINFO($"Created Vulkan logical device.");
            info = new DeviceInfo
            {
                Name          = bestDev.props.DeviceName,
                IsDiscrete    = (bestDev.props.DeviceType == Vk.PhysicalDeviceType.DiscreteGpu),
                VendorName    = VENDOR_ID_LIST.ContainsKey(bestDev.props.VendorId) ? VENDOR_ID_LIST[bestDev.props.VendorId] : "unknown",
                DriverVersion = new AppVersion(bestDev.props.DriverVersion)
            };

            // Retrieve the queues
            queues.Graphics = lDevice.GetQueue(qInfos[0].QueueFamilyIndex, 0);
            queues.Transfer = sepTrans ? lDevice.GetQueue(qInfos[0].QueueFamilyIndex, 1) : queues.Graphics;

            // Save the memory info
            memory = bestDev.memProps;

            LINFO($"Device Info: {info.Name} (S:{bestDev.score} D:{info.IsDiscrete} V:{info.VendorName} DV:{info.DriverVersion.ToString()}).");
            LINFO($"Queue Info: G={queues.Graphics.FamilyIndex}:{queues.Graphics.Index} T={queues.Transfer.FamilyIndex}:{queues.Transfer.Index}.");
        }
예제 #7
0
 public static bool GetPhysicalDevicePresentationSupport(Vk.Instance inst, Vk.PhysicalDevice dev, uint fam)
 => (_glfwGetPhysicalDevicePresentationSupport(inst.Handle, dev.Handle, fam) == 1);
예제 #8
0
        public Swapchain(GraphicsDevice gdevice, Vk.Instance instance, Vk.PhysicalDevice pDevice, Vk.Device device)
        {
            Device            = gdevice;
            _window           = gdevice.Application.Window;
            _vkInstance       = instance;
            _vkPhysicalDevice = pDevice;
            _vkDevice         = device;

            // Create the surface
            long surfHandle = Glfw.CreateWindowSurface(instance, _window.Handle);

            Vk.AllocationCallbacks?acb = null;
            Surface = new VkKhr.SurfaceKhr(instance, ref acb, surfHandle);
            if (VkKhr.PhysicalDeviceExtensions.GetSurfaceSupportKhr(pDevice, gdevice.Queues.Graphics.FamilyIndex, Surface) == Vk.Constant.False)
            {
                LFATAL($"The physical device '{gdevice.Info.Name}' does not support surface presentation.");
                throw new PlatformNotSupportedException("Physical device does not support surface presentation.");
            }
            LINFO("Created Vulkan presentation surface.");

            // Check the surface for swapchain support levels
            var sFmts  = VkKhr.PhysicalDeviceExtensions.GetSurfaceFormatsKhr(pDevice, Surface);
            var pModes = VkKhr.PhysicalDeviceExtensions.GetSurfacePresentModesKhr(pDevice, Surface);

            if (sFmts.Length == 0)
            {
                throw new PlatformNotSupportedException("The chosen device does not support any presentation formats.");
            }
            if (pModes.Length == 0)
            {
                throw new PlatformNotSupportedException("The chosen device does not support any presentation modes.");
            }

            // Choose the best available surface format
            if (sFmts.Length == 1 && sFmts[0].Format == Vk.Format.Undefined)             // We are allowed to pick!
            {
                _surfaceFormat = PREFERRED_SURFACE_FORMATS[0];
            }
            else             // Check if one of the preferred formats is available, otherwise just use the first format given
            {
                var sfmt = PREFERRED_SURFACE_FORMATS.FirstOrDefault(fmt => sFmts.Contains(fmt));
                if (sfmt.Format == 0 && sfmt.ColorSpace == 0)
                {
                    _surfaceFormat = sFmts[0];
                }
                else
                {
                    _surfaceFormat = sfmt;
                }
            }

            // Choose the presentation mode (prefer mailbox -> fifo -> imm)
            _presentMode =
                pModes.Contains(VkKhr.PresentModeKhr.Mailbox) ? VkKhr.PresentModeKhr.Mailbox :
                pModes.Contains(VkKhr.PresentModeKhr.Fifo) ? VkKhr.PresentModeKhr.Fifo :
                VkKhr.PresentModeKhr.Immediate;

            // Prepare the synchronization objects
            _syncObjects.ImageAvailable = new Vk.Semaphore[MAX_INFLIGHT_FRAMES];
            _syncObjects.BlitComplete   = new Vk.Semaphore[MAX_INFLIGHT_FRAMES];
            for (int i = 0; i < MAX_INFLIGHT_FRAMES; ++i)
            {
                _syncObjects.ImageAvailable[i] = device.CreateSemaphore();
                _syncObjects.BlitComplete[i]   = device.CreateSemaphore();
            }

            // Setup the command buffers
            var cpci = new Vk.CommandPoolCreateInfo(_presentQueue.FamilyIndex,
                                                    Vk.CommandPoolCreateFlags.Transient | Vk.CommandPoolCreateFlags.ResetCommandBuffer);

            _commandPool = device.CreateCommandPool(cpci);
            var cbai = new Vk.CommandBufferAllocateInfo(Vk.CommandBufferLevel.Primary, 1);

            _commandBuffer     = _commandPool.AllocateBuffers(cbai)[0];
            _blitFence         = device.CreateFence();     // Do NOT start this signalled, as it is needed in rebuildSwapchain() below
            _rtTransferBarrier = new Vk.ImageMemoryBarrier(
                null,
                new Vk.ImageSubresourceRange(Vk.ImageAspects.Color, 0, 1, 0, 1),
                Vk.Accesses.ColorAttachmentWrite,
                Vk.Accesses.TransferRead,
                Vk.ImageLayout.ColorAttachmentOptimal,
                Vk.ImageLayout.TransferSrcOptimal
                );
            _rtAttachBarrier = new Vk.ImageMemoryBarrier(
                null,
                new Vk.ImageSubresourceRange(Vk.ImageAspects.Color, 0, 1, 0, 1),
                Vk.Accesses.TransferRead,
                Vk.Accesses.ColorAttachmentWrite,
                Vk.ImageLayout.TransferSrcOptimal,
                Vk.ImageLayout.ColorAttachmentOptimal
                );

            // Build the swapchain
            rebuildSwapchain();
        }