Ejemplo n.º 1
0
 /// <summary>
 /// Construct a Graphics object belonging to a window
 /// </summary>
 /// <param name="window"></param>
 public Graphics(WyvernWindow window)
 {
     // Argument checks
     if (window is null)
     {
         throw new ArgumentNullException(nameof(window));
     }
     // Initialize the static part of Graphics if necessary
     InitializeStatic();
     // Store window
     Window = window;
     // Create window surface
     {
         AllocationCallbacks?allocationCallbacks = null;
         Surface = new SurfaceKhr(
             Instance,
             ref allocationCallbacks,
             VkGLFW3.VkGlfw.CreateWindowSurface(Instance.Handle, Window, IntPtr.Zero)
             );
         Surface.PrintDebug();
     }
     // Choose a physical device
     {
         PhysicalDevice = Instance.EnumeratePhysicalDevices()
                          .Where(e => GetDeviceMeetsRequirements(e, Surface))
                          .OrderByDescending(GetDeviceScore)
                          .FirstOrDefault();
         if (PhysicalDevice is null)
         {
             throw new InvalidOperationException("No physical device found that meets the requirements for the application");
         }
         MemoryProperties = PhysicalDevice.GetMemoryProperties();
     }
     // Create default queue families
     {
         ComputeQueueFamily = new QueueFamily(
             $"{Name}'s {nameof(ComputeQueueFamily)}", this, QueueFamily.QueueType.Compute, 2,
             true, ComputeCommandPoolFlags
             );
         GraphicsQueueFamily = new QueueFamily(
             $"{Name}'s {nameof(GraphicsQueueFamily)}", this, QueueFamily.QueueType.Graphics, 2,
             true, GraphicsCommandPoolFlags
             );
         TransferQueueFamily = new QueueFamily(
             $"{Name}'s {nameof(TransferQueueFamily)}", this, QueueFamily.QueueType.Transfer, 2,
             true, TransferCommandPoolFlags
             );
         PresentQueueFamily = new QueueFamily(
             $"{Name}'s {nameof(PresentQueueFamily)}", this, QueueFamily.QueueType.Present, 1,
             false
             );
     }
     // Create a logical device
     {
         // Generate queue create info structs
         var queueCreateInfos = QueueFamilies.Select(queueFamily =>
         {
             // Generate queue priorities
             var priorities = new float[queueFamily.Count];
             for (var i = 0; i < priorities.Length; i++)
             {
                 priorities[i] = 1f - (i / (float)(priorities.Length - 1));
             }
             // Create create info
             var createInfo = new DeviceQueueCreateInfo()
             {
                 QueueFamilyIndex = queueFamily.Index,
                 QueueCount       = queueFamily.Count,
                 QueuePriorities  = priorities
             };
             return(createInfo);
         });
         // Merge multiple queue families' queue create infos
         {
             var alreadyHave       = new List <int>();
             var uniqueCreateInfos = new List <DeviceQueueCreateInfo>();
             foreach (var createInfo in queueCreateInfos.OrderByDescending(e => e.QueueCount))
             {
                 if (!alreadyHave.Contains(createInfo.QueueFamilyIndex))
                 {
                     alreadyHave.Add(createInfo.QueueFamilyIndex);
                     uniqueCreateInfos.Add(createInfo);
                 }
             }
             queueCreateInfos = uniqueCreateInfos;
             foreach (var createInfo in queueCreateInfos)
             {
                 createInfo.PrintDebug();
             }
         }
         // Create device
         Device = PhysicalDevice.CreateDevice(new DeviceCreateInfo()
         {
             EnabledExtensionNames = EnabledDeviceExtensions.ToArray(),
             QueueCreateInfos      = queueCreateInfos.ToArray(),
             EnabledFeatures       = EnabledPhysicalDeviceFeatures
         });
         // Set the queues in the queue families, using those created with the device
         foreach (var family in QueueFamilies)
         {
             var queues = new Queue[family.Count];
             for (var i = 0; i < queues.Length; i++)
             {
                 queues[i] = Device.GetQueue(family.Index, i);
             }
             family.SetQueues(queues);
         }
         // Create and set the command pools in the queue families
         foreach (var family in QueueFamilies)
         {
             // Skip family that shouldn't have a command pool
             if (!family.HasCommandPool)
             {
                 continue;
             }
             // Create command pool
             var commandPool = Device.CreateCommandPool(new CommandPoolCreateInfo()
             {
                 QueueFamilyIndex = family.Index,
                 Flags            = family.CommandPoolFlags
             });
             family.SetCommandPool(commandPool);
         }
     }
     // Create swapchain
     {
         // Query supported capabilities and formats
         var surfaceCapabilities = SurfaceCapabilities;
         var surfaceFormats      = SurfaceFormats;
         var surfacePresentModes = SurfacePresentModes;
         surfaceCapabilities.PrintDebug();
         // Choose the best image format and color space
         {
             var imageFormat = Array.Find(
                 PreferredSwapchainFormats,
                 preferred => surfaceFormats.Any(available => available.Format == preferred)
                 );
             if (imageFormat == Format.Undefined)
             {
                 imageFormat = surfaceFormats.FirstOrDefault().Format;
             }
             if (imageFormat == Format.Undefined)
             {
                 throw new InvalidOperationException("Surface somehow does not support any known image formats");
             }
             SwapchainImageFormat = imageFormat;
             SwapchainColorSpace  = surfaceFormats.First(e => e.Format == SwapchainImageFormat).ColorSpace;
         }
         // Choose the best present mode
         {
             var presentMode = Array.Find(
                 PreferredPresentModes,
                 preferred => surfacePresentModes.Any(available => available == preferred)
                 );
             SwapchainPresentMode = presentMode;
         }
         // Create the swapchain
         SwapchainExtent = surfaceCapabilities.CurrentExtent;
         Swapchain       = Device.CreateSwapchainKhr(new SwapchainCreateInfoKhr(
                                                         surface: Surface,
                                                         imageFormat: SwapchainImageFormat,
                                                         imageExtent: SwapchainExtent,
                                                         preTransform: surfaceCapabilities.CurrentTransform,
                                                         presentMode: SwapchainPresentMode,
                                                         minImageCount: SurfaceCapabilities.MinImageCount,
                                                         imageArrayLayers: SurfaceCapabilities.MaxImageArrayLayers,
                                                         imageSharingMode: SharingMode.Exclusive,
                                                         imageColorSpace: SwapchainColorSpace
                                                         ));
         SwapchainAttachmentImages = Swapchain.GetImages().Select(
             e => new VKImage(
                 e, SwapchainImageFormat,
                 SwapchainExtent,
                 new ImageSubresourceRange(ImageAspects.Color, 0, 1, 0, 1)
                 )
             ).ToArray();
         Swapchain.PrintDebug();
     }
     // Create semaphores & fences
     {
         // Image available semaphore
         ImageAvailableSemaphore = Device.CreateSemaphore();
         ReadyToPresentSemaphore = Device.CreateSemaphore();
         // Swapchain image rendering fences
         RenderToImageFences = new Fence[SwapchainAttachmentImages.Length];
         for (var i = 0; i < RenderToImageFences.Length; i++)
         {
             RenderToImageFences[i] = Device.CreateFence(new FenceCreateInfo(flags: FenceCreateFlags.Signaled));
         }
     }
     // Create content collection
     {
         Content = new ContentCollection(this);
     }
     // Misc
     Stopwatch   = Stopwatch.StartNew();
     CurrentTime = 0.0;
 }