/// <summary>
        /// Function to add the WARP software device.
        /// </summary>
        /// <param name="index">Index of the device.</param>
        /// <param name="factory">The factory used to query the adapter.</param>
        /// <param name="log">The log interface used to send messages to a debug log.</param>
        /// <returns>The video adapter used for WARP software rendering.</returns>
        private static VideoAdapterInfo GetWARPSoftwareDevice(int index, Factory5 factory, IGorgonLog log)
        {
            D3D11.DeviceCreationFlags flags = D3D11.DeviceCreationFlags.None;

            if (GorgonGraphics.IsDebugEnabled)
            {
                flags = D3D11.DeviceCreationFlags.Debug;
            }

            using (Adapter warp = factory.GetWarpAdapter())
                using (Adapter4 warpAdapter4 = warp.QueryInterface <Adapter4>())
                    using (var D3DDevice = new D3D11.Device(warpAdapter4, flags))
                        using (D3D11.Device5 D3DDevice5 = D3DDevice.QueryInterface <D3D11.Device5>())
                        {
                            FeatureSet?featureSet = GetFeatureLevel(D3DDevice5);

                            if (featureSet == null)
                            {
                                log.Print("WARNING: The WARP software adapter does not support the minimum feature set of 12.0. This device will be excluded.", LoggingLevel.All);
                                return(null);
                            }

                            var result = new VideoAdapterInfo(index, warpAdapter4, featureSet.Value, new Dictionary <string, VideoOutputInfo>(), VideoDeviceType.Software);

                            PrintLog(result, log);

                            return(result);
                        }
        }
        /// <summary>
        /// Function to perform an enumeration of the video adapters attached to the system and populate this list.
        /// </summary>
        /// <param name="enumerateWARPDevice"><b>true</b> to enumerate the WARP software device, or <b>false</b> to exclude it.</param>
        /// <param name="log">The log that will capture debug logging messages.</param>
        /// <remarks>
        /// <para>
        /// Use this method to populate a list with information about the video adapters installed in the system.
        /// </para>
        /// <para>
        /// You may include the WARP device, which is a software based device that emulates most of the functionality of a video adapter, by setting the <paramref name="enumerateWARPDevice"/> to <b>true</b>.
        /// </para>
        /// <para>
        /// Gorgon requires a video adapter that is capable of supporting Direct 3D 12.0 at minimum. If no suitable devices are found installed in the computer, then the resulting list will be empty.
        /// </para>
        /// </remarks>
        public static IReadOnlyList <IGorgonVideoAdapterInfo> Enumerate(bool enumerateWARPDevice, IGorgonLog log)
        {
            var devices = new List <IGorgonVideoAdapterInfo>();

            if (log == null)
            {
                log = GorgonLog.NullLog;
            }

            using (var factory2 = new Factory2(GorgonGraphics.IsDebugEnabled))
                using (Factory5 factory5 = factory2.QueryInterface <Factory5>())
                {
                    int adapterCount = factory5.GetAdapterCount1();

                    log.Print("Enumerating video adapters...", LoggingLevel.Simple);

                    // Begin gathering device information.
                    for (int i = 0; i < adapterCount; i++)
                    {
                        // Get the video adapter information.
                        using (Adapter1 adapter1 = factory5.GetAdapter1(i))
                            using (Adapter4 adapter = adapter1.QueryInterface <Adapter4>())
                            {
                                // ReSharper disable BitwiseOperatorOnEnumWithoutFlags
                                if (((adapter.Desc3.Flags & AdapterFlags3.Remote) == AdapterFlags3.Remote) ||
                                    ((adapter.Desc3.Flags & AdapterFlags3.Software) == AdapterFlags3.Software))
                                {
                                    continue;
                                }
                                // ReSharper restore BitwiseOperatorOnEnumWithoutFlags

                                D3D11.DeviceCreationFlags flags = D3D11.DeviceCreationFlags.None;

                                if (GorgonGraphics.IsDebugEnabled)
                                {
                                    flags = D3D11.DeviceCreationFlags.Debug;
                                }

                                // We create a D3D device here to filter out unsupported video modes from the format list.
                                using (var D3DDevice = new D3D11.Device(adapter, flags, D3D.FeatureLevel.Level_12_1, D3D.FeatureLevel.Level_12_0))
                                    using (D3D11.Device5 D3DDevice5 = D3DDevice.QueryInterface <D3D11.Device5>())
                                    {
                                        D3DDevice5.DebugName = "Output enumerator device.";

                                        FeatureSet?featureSet = GetFeatureLevel(D3DDevice5);

                                        // Do not enumerate this device if its feature set is not supported.
                                        if (featureSet == null)
                                        {
                                            log.Print("This video adapter is not supported by Gorgon and will be skipped.", LoggingLevel.Verbose);
                                            continue;
                                        }

                                        Dictionary <string, VideoOutputInfo> outputs = GetOutputs(D3DDevice5, adapter, adapter.GetOutputCount(), log);

                                        if (outputs.Count <= 0)
                                        {
                                            log.Print($"WARNING: Video adapter {adapter.Description1.Description.Replace("\0", string.Empty)} has no outputs. Full screen mode will not be possible.",
                                                      LoggingLevel.Verbose);
                                        }

                                        var videoAdapter = new VideoAdapterInfo(i, adapter, featureSet.Value, outputs, VideoDeviceType.Hardware);

                                        devices.Add(videoAdapter);
                                        PrintLog(videoAdapter, log);
                                    }
                            }
                    }

                    // Get software devices.
                    if (!enumerateWARPDevice)
                    {
                        return(devices);
                    }

                    VideoAdapterInfo device = GetWARPSoftwareDevice(devices.Count, factory5, log);

                    if (device != null)
                    {
                        devices.Add(device);
                    }
                }

            log.Print("Found {0} video adapters.", LoggingLevel.Simple, devices.Count);

            return(devices);
        }
        /// <summary>
        /// Function to retrieve the outputs attached to a video adapter.
        /// </summary>
        /// <param name="device">The Direct 3D device used to filter display modes.</param>
        /// <param name="adapter">The adapter to retrieve the outputs from.</param>
        /// <param name="outputCount">The number of outputs for the device.</param>
        /// <param name="log">The logging interface used to capture debug messages.</param>
        /// <returns>A list if video output info values.</returns>
        private static Dictionary <string, VideoOutputInfo> GetOutputs(D3D11.Device5 device, Adapter4 adapter, int outputCount, IGorgonLog log)
        {
            var result = new Dictionary <string, VideoOutputInfo>(StringComparer.OrdinalIgnoreCase);

            // Devices created under RDP/TS do not support output selection.
            if (SystemInformation.TerminalServerSession)
            {
                log.Print("Devices under terminal services and software devices devices do not use outputs, no outputs enumerated.", LoggingLevel.Intermediate);
                return(result);
            }

            for (int i = 0; i < outputCount; ++i)
            {
                using (Output output = adapter.GetOutput(i))
                    using (Output6 output6 = output.QueryInterface <Output6>())
                    {
                        var outputInfo = new VideoOutputInfo(i, output6, GetVideoModes(device, output6));

                        if (outputInfo.VideoModes.Count == 0)
                        {
                            log.Print($"Output '{output.Description.DeviceName}' on adapter '{adapter.Description1.Description}' has no full screen video modes.",
                                      LoggingLevel.Intermediate);
                        }

                        result.Add(output.Description.DeviceName, outputInfo);
                    }
            }

            return(result);
        }