1 // Copyright 2016 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <memory>
8 #include <optional>
9 #include <string>
10 #include <vector>
11 
12 #include "Common/CommonTypes.h"
13 #include "Common/WindowSystemInfo.h"
14 #include "VideoBackends/Vulkan/Constants.h"
15 #include "VideoCommon/VideoConfig.h"
16 
17 namespace Vulkan
18 {
19 class VulkanContext
20 {
21 public:
22   VulkanContext(VkInstance instance, VkPhysicalDevice physical_device);
23   ~VulkanContext();
24 
25   // Determines if the Vulkan validation layer is available on the system.
26   static bool CheckValidationLayerAvailablility();
27 
28   // Helper method to create a Vulkan instance.
29   static VkInstance CreateVulkanInstance(WindowSystemType wstype, bool enable_debug_report,
30                                          bool enable_validation_layer);
31 
32   // Returns a list of Vulkan-compatible GPUs.
33   using GPUList = std::vector<VkPhysicalDevice>;
34   static GPUList EnumerateGPUs(VkInstance instance);
35 
36   // Populates backend/video config.
37   // These are public so that the backend info can be populated without creating a context.
38   static void PopulateBackendInfo(VideoConfig* config);
39   static void PopulateBackendInfoAdapters(VideoConfig* config, const GPUList& gpu_list);
40   static void PopulateBackendInfoFeatures(VideoConfig* config, VkPhysicalDevice gpu,
41                                           const VkPhysicalDeviceProperties& properties,
42                                           const VkPhysicalDeviceFeatures& features);
43   static void PopulateBackendInfoMultisampleModes(VideoConfig* config, VkPhysicalDevice gpu,
44                                                   const VkPhysicalDeviceProperties& properties);
45 
46   // Creates a Vulkan device context.
47   // This assumes that PopulateBackendInfo and PopulateBackendInfoAdapters has already
48   // been called for the specified VideoConfig.
49   static std::unique_ptr<VulkanContext> Create(VkInstance instance, VkPhysicalDevice gpu,
50                                                VkSurfaceKHR surface, bool enable_debug_reports,
51                                                bool enable_validation_layer);
52 
53   // Enable/disable debug message runtime.
54   bool EnableDebugReports();
55   void DisableDebugReports();
56 
57   // Global state accessors
GetVulkanInstance()58   VkInstance GetVulkanInstance() const { return m_instance; }
GetPhysicalDevice()59   VkPhysicalDevice GetPhysicalDevice() const { return m_physical_device; }
GetDevice()60   VkDevice GetDevice() const { return m_device; }
GetGraphicsQueue()61   VkQueue GetGraphicsQueue() const { return m_graphics_queue; }
GetGraphicsQueueFamilyIndex()62   u32 GetGraphicsQueueFamilyIndex() const { return m_graphics_queue_family_index; }
GetPresentQueue()63   VkQueue GetPresentQueue() const { return m_present_queue; }
GetPresentQueueFamilyIndex()64   u32 GetPresentQueueFamilyIndex() const { return m_present_queue_family_index; }
GetGraphicsQueueProperties()65   const VkQueueFamilyProperties& GetGraphicsQueueProperties() const
66   {
67     return m_graphics_queue_properties;
68   }
GetDeviceMemoryProperties()69   const VkPhysicalDeviceMemoryProperties& GetDeviceMemoryProperties() const
70   {
71     return m_device_memory_properties;
72   }
GetDeviceProperties()73   const VkPhysicalDeviceProperties& GetDeviceProperties() const { return m_device_properties; }
GetDeviceFeatures()74   const VkPhysicalDeviceFeatures& GetDeviceFeatures() const { return m_device_features; }
GetDeviceLimits()75   const VkPhysicalDeviceLimits& GetDeviceLimits() const { return m_device_properties.limits; }
76   // Support bits
SupportsAnisotropicFiltering()77   bool SupportsAnisotropicFiltering() const
78   {
79     return m_device_features.samplerAnisotropy == VK_TRUE;
80   }
SupportsPreciseOcclusionQueries()81   bool SupportsPreciseOcclusionQueries() const
82   {
83     return m_device_features.occlusionQueryPrecise == VK_TRUE;
84   }
GetShaderSubgroupSize()85   u32 GetShaderSubgroupSize() const { return m_shader_subgroup_size; }
SupportsShaderSubgroupOperations()86   bool SupportsShaderSubgroupOperations() const { return m_supports_shader_subgroup_operations; }
87 
88   // Helpers for getting constants
GetUniformBufferAlignment()89   VkDeviceSize GetUniformBufferAlignment() const
90   {
91     return m_device_properties.limits.minUniformBufferOffsetAlignment;
92   }
GetTexelBufferAlignment()93   VkDeviceSize GetTexelBufferAlignment() const
94   {
95     return m_device_properties.limits.minUniformBufferOffsetAlignment;
96   }
GetBufferImageGranularity()97   VkDeviceSize GetBufferImageGranularity() const
98   {
99     return m_device_properties.limits.bufferImageGranularity;
100   }
GetMaxSamplerAnisotropy()101   float GetMaxSamplerAnisotropy() const { return m_device_properties.limits.maxSamplerAnisotropy; }
102   // Finds a memory type index for the specified memory properties and the bits returned by
103   // vkGetImageMemoryRequirements
104   std::optional<u32> GetMemoryType(u32 bits, VkMemoryPropertyFlags properties, bool strict,
105                                    bool* is_coherent = nullptr);
106 
107   // Finds a memory type for upload or readback buffers.
108   u32 GetUploadMemoryType(u32 bits, bool* is_coherent = nullptr);
109   u32 GetReadbackMemoryType(u32 bits, bool* is_coherent = nullptr);
110 
111   // Returns true if the specified extension is supported and enabled.
112   bool SupportsDeviceExtension(const char* name) const;
113 
114   // Returns true if exclusive fullscreen is supported for the given surface.
115   bool SupportsExclusiveFullscreen(const WindowSystemInfo& wsi, VkSurfaceKHR surface);
116 
117 #ifdef WIN32
118   // Returns the platform-specific exclusive fullscreen structure.
119   VkSurfaceFullScreenExclusiveWin32InfoEXT
120   GetPlatformExclusiveFullscreenInfo(const WindowSystemInfo& wsi);
121 #endif
122 
123 private:
124   static bool SelectInstanceExtensions(std::vector<const char*>* extension_list,
125                                        WindowSystemType wstype, bool enable_debug_report);
126   bool SelectDeviceExtensions(bool enable_surface);
127   bool SelectDeviceFeatures();
128   bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer);
129   void InitDriverDetails();
130   void PopulateShaderSubgroupSupport();
131 
132   VkInstance m_instance = VK_NULL_HANDLE;
133   VkPhysicalDevice m_physical_device = VK_NULL_HANDLE;
134   VkDevice m_device = VK_NULL_HANDLE;
135 
136   VkQueue m_graphics_queue = VK_NULL_HANDLE;
137   u32 m_graphics_queue_family_index = 0;
138   VkQueue m_present_queue = VK_NULL_HANDLE;
139   u32 m_present_queue_family_index = 0;
140   VkQueueFamilyProperties m_graphics_queue_properties = {};
141 
142   VkDebugReportCallbackEXT m_debug_report_callback = VK_NULL_HANDLE;
143 
144   VkPhysicalDeviceFeatures m_device_features = {};
145   VkPhysicalDeviceProperties m_device_properties = {};
146   VkPhysicalDeviceMemoryProperties m_device_memory_properties = {};
147 
148   u32 m_shader_subgroup_size = 1;
149   bool m_supports_shader_subgroup_operations = false;
150 
151   std::vector<std::string> m_device_extensions;
152 };
153 
154 extern std::unique_ptr<VulkanContext> g_vulkan_context;
155 
156 }  // namespace Vulkan
157