CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Common/GPU/Vulkan/VulkanContext.h
Views: 1401
#pragma once12#include <cstring>3#include <string>4#include <vector>5#include <utility>6#include <functional>78#include "Common/Log.h"9#include "Common/GPU/Vulkan/VulkanLoader.h"10#include "Common/GPU/Vulkan/VulkanDebug.h"11#include "Common/GPU/Vulkan/VulkanAlloc.h"12#include "Common/GPU/Vulkan/VulkanProfiler.h"1314// Enable or disable a simple logging profiler for Vulkan.15// Mostly useful for profiling texture uploads currently, but could be useful for16// other things as well. We also have a nice integrated render pass profiler in the queue17// runner, but this one is more convenient for transient events.1819#define VK_PROFILE_BEGIN(vulkan, cmd, stage, ...) vulkan->GetProfiler()->Begin(cmd, stage, __VA_ARGS__);20#define VK_PROFILE_END(vulkan, cmd, stage) vulkan->GetProfiler()->End(cmd, stage);2122enum {23VULKAN_FLAG_VALIDATE = 1,24VULKAN_FLAG_PRESENT_MAILBOX = 2,25VULKAN_FLAG_PRESENT_IMMEDIATE = 4,26VULKAN_FLAG_PRESENT_FIFO_RELAXED = 8,27VULKAN_FLAG_PRESENT_FIFO = 16,28};2930enum {31VULKAN_VENDOR_NVIDIA = 0x000010de,32VULKAN_VENDOR_INTEL = 0x00008086, // Haha!33VULKAN_VENDOR_AMD = 0x00001002,34VULKAN_VENDOR_ARM = 0x000013B5, // Mali35VULKAN_VENDOR_QUALCOMM = 0x00005143,36VULKAN_VENDOR_IMGTEC = 0x00001010, // PowerVR37VULKAN_VENDOR_APPLE = 0x0000106b, // Apple through MoltenVK38VULKAN_VENDOR_MESA = 0x00010005, // lavapipe39};4041VK_DEFINE_HANDLE(VmaAllocator);42VK_DEFINE_HANDLE(VmaAllocation);4344std::string VulkanVendorString(uint32_t vendorId);4546template<class R, class T> inline void ChainStruct(R &root, T *newStruct) {47newStruct->pNext = root.pNext;48root.pNext = newStruct;49}5051// Not all will be usable on all platforms, of course...52enum WindowSystem {53#ifdef _WIN3254WINDOWSYSTEM_WIN32,55#endif56#ifdef __ANDROID__57WINDOWSYSTEM_ANDROID,58#endif59#ifdef VK_USE_PLATFORM_METAL_EXT60WINDOWSYSTEM_METAL_EXT,61#endif62#ifdef VK_USE_PLATFORM_XLIB_KHR63WINDOWSYSTEM_XLIB,64#endif65#ifdef VK_USE_PLATFORM_XCB_KHR66WINDOWSYSTEM_XCB,67#endif68#ifdef VK_USE_PLATFORM_WAYLAND_KHR69WINDOWSYSTEM_WAYLAND,70#endif71#ifdef VK_USE_PLATFORM_DISPLAY_KHR72WINDOWSYSTEM_DISPLAY,73#endif74};7576struct VulkanPhysicalDeviceInfo {77VkFormat preferredDepthStencilFormat;78bool canBlitToPreferredDepthStencilFormat;79};8081class VulkanProfiler;82class VulkanContext;8384// Extremely rough split of capabilities.85enum class PerfClass {86SLOW,87FAST,88};8990// This is a bit repetitive...91class VulkanDeleteList {92struct BufferWithAlloc {93VkBuffer buffer;94VmaAllocation alloc;95};96struct ImageWithAlloc {97VkImage image;98VmaAllocation alloc;99};100101struct Callback {102explicit Callback(void(*f)(VulkanContext *vulkan, void *userdata), void *u)103: func(f), userdata(u) {104}105106void (*func)(VulkanContext *vulkan, void *userdata);107void *userdata;108};109110public:111// NOTE: These all take reference handles so they can zero the input value.112void QueueDeleteCommandPool(VkCommandPool &pool) { _dbg_assert_(pool != VK_NULL_HANDLE); cmdPools_.push_back(pool); pool = VK_NULL_HANDLE; }113void QueueDeleteDescriptorPool(VkDescriptorPool &pool) { _dbg_assert_(pool != VK_NULL_HANDLE); descPools_.push_back(pool); pool = VK_NULL_HANDLE; }114void QueueDeleteShaderModule(VkShaderModule &module) { _dbg_assert_(module != VK_NULL_HANDLE); modules_.push_back(module); module = VK_NULL_HANDLE; }115void QueueDeleteBuffer(VkBuffer &buffer) { _dbg_assert_(buffer != VK_NULL_HANDLE); buffers_.push_back(buffer); buffer = VK_NULL_HANDLE; }116void QueueDeleteBufferView(VkBufferView &bufferView) { _dbg_assert_(bufferView != VK_NULL_HANDLE); bufferViews_.push_back(bufferView); bufferView = VK_NULL_HANDLE; }117void QueueDeleteImageView(VkImageView &imageView) { _dbg_assert_(imageView != VK_NULL_HANDLE); imageViews_.push_back(imageView); imageView = VK_NULL_HANDLE; }118void QueueDeleteDeviceMemory(VkDeviceMemory &deviceMemory) { _dbg_assert_(deviceMemory != VK_NULL_HANDLE); deviceMemory_.push_back(deviceMemory); deviceMemory = VK_NULL_HANDLE; }119void QueueDeleteSampler(VkSampler &sampler) { _dbg_assert_(sampler != VK_NULL_HANDLE); samplers_.push_back(sampler); sampler = VK_NULL_HANDLE; }120void QueueDeletePipeline(VkPipeline &pipeline) { _dbg_assert_(pipeline != VK_NULL_HANDLE); pipelines_.push_back(pipeline); pipeline = VK_NULL_HANDLE; }121void QueueDeletePipelineCache(VkPipelineCache &pipelineCache) { _dbg_assert_(pipelineCache != VK_NULL_HANDLE); pipelineCaches_.push_back(pipelineCache); pipelineCache = VK_NULL_HANDLE; }122void QueueDeleteRenderPass(VkRenderPass &renderPass) { _dbg_assert_(renderPass != VK_NULL_HANDLE); renderPasses_.push_back(renderPass); renderPass = VK_NULL_HANDLE; }123void QueueDeleteFramebuffer(VkFramebuffer &framebuffer) { _dbg_assert_(framebuffer != VK_NULL_HANDLE); framebuffers_.push_back(framebuffer); framebuffer = VK_NULL_HANDLE; }124void QueueDeletePipelineLayout(VkPipelineLayout &pipelineLayout) { _dbg_assert_(pipelineLayout != VK_NULL_HANDLE); pipelineLayouts_.push_back(pipelineLayout); pipelineLayout = VK_NULL_HANDLE; }125void QueueDeleteDescriptorSetLayout(VkDescriptorSetLayout &descSetLayout) { _dbg_assert_(descSetLayout != VK_NULL_HANDLE); descSetLayouts_.push_back(descSetLayout); descSetLayout = VK_NULL_HANDLE; }126void QueueDeleteQueryPool(VkQueryPool &queryPool) { _dbg_assert_(queryPool != VK_NULL_HANDLE); queryPools_.push_back(queryPool); queryPool = VK_NULL_HANDLE; }127void QueueCallback(void (*func)(VulkanContext *vulkan, void *userdata), void *userdata) { callbacks_.push_back(Callback(func, userdata)); }128129void QueueDeleteBufferAllocation(VkBuffer &buffer, VmaAllocation &alloc) {130_dbg_assert_(buffer != VK_NULL_HANDLE);131buffersWithAllocs_.push_back(BufferWithAlloc{ buffer, alloc });132buffer = VK_NULL_HANDLE;133alloc = VK_NULL_HANDLE;134}135void QueueDeleteImageAllocation(VkImage &image, VmaAllocation &alloc) {136_dbg_assert_(image != VK_NULL_HANDLE && alloc != VK_NULL_HANDLE);137imagesWithAllocs_.push_back(ImageWithAlloc{ image, alloc });138image = VK_NULL_HANDLE;139alloc = VK_NULL_HANDLE;140}141142void Take(VulkanDeleteList &del);143void PerformDeletes(VulkanContext *vulkan, VmaAllocator allocator);144145int GetLastDeleteCount() const {146return deleteCount_;147}148149private:150std::vector<VkCommandPool> cmdPools_;151std::vector<VkDescriptorPool> descPools_;152std::vector<VkShaderModule> modules_;153std::vector<VkBuffer> buffers_;154std::vector<BufferWithAlloc> buffersWithAllocs_;155std::vector<VkBufferView> bufferViews_;156std::vector<ImageWithAlloc> imagesWithAllocs_;157std::vector<VkImageView> imageViews_;158std::vector<VkDeviceMemory> deviceMemory_;159std::vector<VkSampler> samplers_;160std::vector<VkPipeline> pipelines_;161std::vector<VkPipelineCache> pipelineCaches_;162std::vector<VkRenderPass> renderPasses_;163std::vector<VkFramebuffer> framebuffers_;164std::vector<VkPipelineLayout> pipelineLayouts_;165std::vector<VkDescriptorSetLayout> descSetLayouts_;166std::vector<VkQueryPool> queryPools_;167std::vector<Callback> callbacks_;168int deleteCount_ = 0;169};170171// VulkanContext manages the device and swapchain, and deferred deletion of objects.172class VulkanContext {173public:174VulkanContext();175~VulkanContext();176177struct CreateInfo {178const char *app_name;179int app_ver;180uint32_t flags;181};182183VkResult CreateInstance(const CreateInfo &info);184void DestroyInstance();185186int GetBestPhysicalDevice();187int GetPhysicalDeviceByName(const std::string &name);188189// Convenience method to avoid code duplication.190// If it returns false, delete the context.191bool CreateInstanceAndDevice(const CreateInfo &info);192193// The coreVersion is to avoid enabling extensions that are merged into core Vulkan from a certain version.194bool EnableInstanceExtension(const char *extension, uint32_t coreVersion);195bool EnableDeviceExtension(const char *extension, uint32_t coreVersion);196197// Was previously two functions, ChooseDevice and CreateDevice.198VkResult CreateDevice(int physical_device);199200const std::string &InitError() const { return init_error_; }201202VkDevice GetDevice() const { return device_; }203VkInstance GetInstance() const { return instance_; }204uint32_t GetFlags() const { return flags_; }205void UpdateFlags(uint32_t flags) { flags_ = flags; }206207VulkanDeleteList &Delete() { return globalDeleteList_; }208209// The parameters are whatever the chosen window system wants.210// The extents will be automatically determined.211VkResult InitSurface(WindowSystem winsys, void *data1, void *data2);212VkResult ReinitSurface();213214bool InitSwapchain();215void SetCbGetDrawSize(std::function<VkExtent2D()>);216217void DestroySwapchain();218void DestroySurface();219220void DestroyDevice();221222void PerformPendingDeletes();223void WaitUntilQueueIdle();224225// Utility functions for shorter code226VkFence CreateFence(bool presignalled);227bool CreateShaderModule(const std::vector<uint32_t> &spirv, VkShaderModule *shaderModule, const char *tag);228229int GetBackbufferWidth() { return (int)swapChainExtent_.width; }230int GetBackbufferHeight() { return (int)swapChainExtent_.height; }231232void BeginFrame(VkCommandBuffer firstCommandBuffer);233void EndFrame();234235VulkanProfiler *GetProfiler() {236return &frame_[curFrame_].profiler;237}238239// Simple workaround for the casting warning.240template <class T>241void SetDebugName(T handle, VkObjectType type, const char *name) {242if (extensionsLookup_.EXT_debug_utils && handle != VK_NULL_HANDLE) {243_dbg_assert_(handle != VK_NULL_HANDLE);244SetDebugNameImpl((uint64_t)handle, type, name);245}246}247bool DebugLayerEnabled() const {248return extensionsLookup_.EXT_debug_utils;249}250251bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);252253VkPhysicalDevice GetPhysicalDevice(int n) const {254return physical_devices_[n];255}256VkPhysicalDevice GetCurrentPhysicalDevice() const {257return physical_devices_[physical_device_];258}259int GetCurrentPhysicalDeviceIndex() const {260return physical_device_;261}262int GetNumPhysicalDevices() const {263return (int)physical_devices_.size();264}265266VkQueue GetGraphicsQueue() const {267return gfx_queue_;268}269270int GetGraphicsQueueFamilyIndex() const {271return graphics_queue_family_index_;272}273274struct PhysicalDeviceProps {275VkPhysicalDeviceProperties properties;276VkPhysicalDevicePushDescriptorPropertiesKHR pushDescriptorProperties;277VkPhysicalDeviceExternalMemoryHostPropertiesEXT externalMemoryHostProperties;278VkPhysicalDeviceDepthStencilResolveProperties depthStencilResolve;279};280281struct AllPhysicalDeviceFeatures {282VkPhysicalDeviceFeatures standard;283VkPhysicalDeviceMultiviewFeatures multiview;284VkPhysicalDevicePresentWaitFeaturesKHR presentWait;285VkPhysicalDevicePresentIdFeaturesKHR presentId;286VkPhysicalDeviceProvokingVertexFeaturesEXT provokingVertex;287};288289const PhysicalDeviceProps &GetPhysicalDeviceProperties(int i = -1) const {290if (i < 0)291i = GetCurrentPhysicalDeviceIndex();292return physicalDeviceProperties_[i];293}294295const VkQueueFamilyProperties &GetQueueFamilyProperties(int family) const {296return queueFamilyProperties_[family];297}298299VkResult GetInstanceLayerExtensionList(const char *layerName, std::vector<VkExtensionProperties> &extensions);300VkResult GetInstanceLayerProperties();301302VkResult GetDeviceLayerExtensionList(const char *layerName, std::vector<VkExtensionProperties> &extensions);303VkResult GetDeviceLayerProperties();304305const std::vector<VkExtensionProperties> &GetDeviceExtensionsAvailable() const {306return device_extension_properties_;307}308const std::vector<const char *> &GetDeviceExtensionsEnabled() const {309return device_extensions_enabled_;310}311312const std::vector<VkExtensionProperties> &GetInstanceExtensionsAvailable() const {313return instance_extension_properties_;314}315const std::vector<const char *> &GetInstanceExtensionsEnabled() const {316return instance_extensions_enabled_;317}318319const VkPhysicalDeviceMemoryProperties &GetMemoryProperties() const {320return memory_properties_;321}322323struct PhysicalDeviceFeatures {324AllPhysicalDeviceFeatures available{};325AllPhysicalDeviceFeatures enabled{};326};327328const PhysicalDeviceFeatures &GetDeviceFeatures() const { return deviceFeatures_; }329const VulkanPhysicalDeviceInfo &GetDeviceInfo() const { return deviceInfo_; }330const VkSurfaceCapabilitiesKHR &GetSurfaceCapabilities() const { return surfCapabilities_; }331332bool IsInstanceExtensionAvailable(const char *extensionName) const {333for (const auto &iter : instance_extension_properties_) {334if (!strcmp(extensionName, iter.extensionName))335return true;336}337338// Also search through the layers, one of them might carry the extension (especially DEBUG_utils)339for (const auto &iter : instance_layer_properties_) {340for (const auto &ext : iter.extensions) {341if (!strcmp(extensionName, ext.extensionName)) {342return true;343}344}345}346347return false;348}349350bool IsDeviceExtensionAvailable(const char *name) const {351for (auto &iter : device_extension_properties_) {352if (!strcmp(name, iter.extensionName))353return true;354}355return false;356}357358int GetInflightFrames() const {359// out of MAX_INFLIGHT_FRAMES.360return inflightFrames_;361}362363// Don't call while a frame is in progress.364void UpdateInflightFrames(int n);365366int GetCurFrame() const {367return curFrame_;368}369370VkSwapchainKHR GetSwapchain() const {371return swapchain_;372}373VkFormat GetSwapchainFormat() const {374return swapchainFormat_;375}376377void SetProfilerEnabledPtr(bool *enabled) {378for (auto &frame : frame_) {379frame.profiler.SetEnabledPtr(enabled);380}381}382383// 1 for no frame overlap and thus minimal latency but worst performance.384// 2 is an OK compromise, while 3 performs best but risks slightly higher latency.385enum {386MAX_INFLIGHT_FRAMES = 3,387};388389const VulkanExtensions &Extensions() { return extensionsLookup_; }390391PerfClass DevicePerfClass() const {392return devicePerfClass_;393}394395void GetImageMemoryRequirements(VkImage image, VkMemoryRequirements *mem_reqs, bool *dedicatedAllocation);396397VmaAllocator Allocator() const {398return allocator_;399}400401const std::vector<VkSurfaceFormatKHR> &SurfaceFormats() {402return surfFormats_;403}404405VkPresentModeKHR GetPresentMode() const {406return presentMode_;407}408409std::vector<VkPresentModeKHR> GetAvailablePresentModes() const {410return availablePresentModes_;411}412413int GetLastDeleteCount() const {414return frame_[curFrame_].deleteList.GetLastDeleteCount();415}416417u32 InstanceApiVersion() const {418return vulkanInstanceApiVersion_;419}420421u32 DeviceApiVersion() const {422return vulkanDeviceApiVersion_;423}424425private:426bool ChooseQueue();427428void SetDebugNameImpl(uint64_t handle, VkObjectType type, const char *name);429430VkResult InitDebugUtilsCallback();431432// A layer can expose extensions, keep track of those extensions here.433struct LayerProperties {434VkLayerProperties properties;435std::vector<VkExtensionProperties> extensions;436};437438bool CheckLayers(const std::vector<LayerProperties> &layer_props, const std::vector<const char *> &layer_names) const;439440WindowSystem winsys_{};441442// Don't use the real types here to avoid having to include platform-specific stuff443// that we really don't want in everything that uses VulkanContext.444void *winsysData1_ = nullptr;445void *winsysData2_ = nullptr;446std::function<VkExtent2D()> cbGetDrawSize_;447448VkInstance instance_ = VK_NULL_HANDLE;449VkDevice device_ = VK_NULL_HANDLE;450VkQueue gfx_queue_ = VK_NULL_HANDLE;451VkSurfaceKHR surface_ = VK_NULL_HANDLE;452u32 vulkanInstanceApiVersion_ = 0;453u32 vulkanDeviceApiVersion_ = 0;454455std::string init_error_;456std::vector<const char *> instance_layer_names_;457std::vector<LayerProperties> instance_layer_properties_;458459std::vector<const char *> instance_extensions_enabled_;460std::vector<VkExtensionProperties> instance_extension_properties_;461462std::vector<const char *> device_layer_names_;463std::vector<LayerProperties> device_layer_properties_;464465std::vector<const char *> device_extensions_enabled_;466std::vector<VkExtensionProperties> device_extension_properties_;467VulkanExtensions extensionsLookup_{};468469std::vector<VkPhysicalDevice> physical_devices_;470471int physical_device_ = -1;472473uint32_t graphics_queue_family_index_ = -1;474std::vector<PhysicalDeviceProps> physicalDeviceProperties_;475std::vector<VkQueueFamilyProperties> queueFamilyProperties_;476477VkPhysicalDeviceMemoryProperties memory_properties_{};478479// Custom collection of things that are good to know480VulkanPhysicalDeviceInfo deviceInfo_{};481482// Swap chain extent483VkExtent2D swapChainExtent_{};484485int flags_ = 0;486PerfClass devicePerfClass_ = PerfClass::SLOW;487488int inflightFrames_ = MAX_INFLIGHT_FRAMES;489490struct FrameData {491FrameData() {}492VulkanDeleteList deleteList;493VulkanProfiler profiler;494};495FrameData frame_[MAX_INFLIGHT_FRAMES];496int curFrame_ = 0;497498// At the end of the frame, this is copied into the frame's delete list, so it can be processed499// the next time the frame comes around again.500VulkanDeleteList globalDeleteList_;501502std::vector<VkDebugUtilsMessengerEXT> utils_callbacks;503504VkSwapchainKHR swapchain_ = VK_NULL_HANDLE;505VkFormat swapchainFormat_ = VK_FORMAT_UNDEFINED;506507uint32_t queue_count = 0;508509PhysicalDeviceFeatures deviceFeatures_;510511VkSurfaceCapabilitiesKHR surfCapabilities_{};512std::vector<VkSurfaceFormatKHR> surfFormats_{};513514VkPresentModeKHR presentMode_ = VK_PRESENT_MODE_FIFO_KHR;515std::vector<VkPresentModeKHR> availablePresentModes_;516517std::vector<VkCommandBuffer> cmdQueue_;518519VmaAllocator allocator_ = VK_NULL_HANDLE;520};521522// GLSL compiler523void init_glslang();524void finalize_glslang();525526enum class GLSLVariant {527VULKAN,528GL140,529GLES300,530};531532bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *sourceCode, GLSLVariant variant, std::vector<uint32_t> &spirv, std::string *errorMessage);533534const char *VulkanColorSpaceToString(VkColorSpaceKHR colorSpace);535const char *VulkanFormatToString(VkFormat format);536const char *VulkanPresentModeToString(VkPresentModeKHR presentMode);537const char *VulkanImageLayoutToString(VkImageLayout imageLayout);538539std::string FormatDriverVersion(const VkPhysicalDeviceProperties &props);540std::string FormatAPIVersion(u32 version);541542// Simple heuristic.543bool IsHashMaliDriverVersion(const VkPhysicalDeviceProperties &props);544545extern VulkanLogOptions g_LogOptions;546547548