Restructured file, removed friends, added public interface
This commit is contained in:
parent
3a6ce0217a
commit
5d254bc513
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,7 @@
|
||||
#include "vertex.hpp"
|
||||
#include "shape.hpp"
|
||||
#include "vulkan_util.hpp"
|
||||
#include "vulkan_allocator.hpp"
|
||||
|
||||
|
||||
#include <gz-util/log.hpp>
|
||||
@ -23,11 +24,10 @@
|
||||
#include <vector>
|
||||
|
||||
namespace gz::vk {
|
||||
|
||||
constexpr bool throwExceptionOnValidationError = true;
|
||||
constexpr gz::Color VULKAN_MESSAGE_PREFIX_COLOR = gz::Color::BO_BLUE;
|
||||
constexpr gz::Color VULKAN_MESSAGE_TIME_COLOR = gz::Color::BLUE;
|
||||
const std::string CONFIG_FILE = "vulkan.conf";
|
||||
const int MAX_FRAMES_IN_FLIGHT = 3;
|
||||
#define SettingsTypes uint32_t, bool, float
|
||||
|
||||
/* const std::string MODEL_PATH = "models/gazebo-3d-model/gazebo.obj"; */
|
||||
@ -40,6 +40,7 @@ namespace gz::vk {
|
||||
{ "framerate", "60" },
|
||||
{ "anisotropy_enable", "false" },
|
||||
{ "max_anisotropy", "1" },
|
||||
{ "max_frames_in_flight", "3" },
|
||||
/* { "", "" } */
|
||||
};
|
||||
|
||||
@ -51,14 +52,22 @@ namespace gz::vk {
|
||||
constexpr VkAllocationCallbacks* NO_ALLOC = nullptr;
|
||||
const size_t VERTEX_BUFFER_SIZE = 512;
|
||||
const size_t INDEX_BUFFER_SIZE = 512;
|
||||
enum InstanceCommandPool {
|
||||
POOL_GRAPHICS, POOL_TRANSFER
|
||||
};
|
||||
|
||||
/**
|
||||
* @nosubgrouping
|
||||
*/
|
||||
class VulkanInstance {
|
||||
friend class Renderer;
|
||||
friend class Renderer2D;
|
||||
friend class Renderer3D;
|
||||
friend class TextureManager;
|
||||
friend class TextureAtlas;
|
||||
public:
|
||||
VulkanInstance(gz::SettingsManagerCreateInfo<SettingsTypes>smCI) : settings(smCI) {};
|
||||
/**
|
||||
* @name Public Interface: For the "creator" of the instance
|
||||
* @details
|
||||
* These functions will probably called from your `main` function and loop.
|
||||
*/
|
||||
/// @{
|
||||
VulkanInstance(gz::SettingsManagerCreateInfo<SettingsTypes>smCI) : settings(smCI), allocator(*this) {};
|
||||
/**
|
||||
* @brief Initializes the vulkan instance
|
||||
* @details
|
||||
@ -87,9 +96,19 @@ namespace gz::vk {
|
||||
* -# Call endFrameDraw
|
||||
*/
|
||||
uint32_t beginFrameDraw();
|
||||
void submitThisFrame(VkCommandBuffer& cmdBuffer);
|
||||
void endFrameDraw(uint32_t imageIndex);
|
||||
GLFWwindow* window;
|
||||
void cleanup();
|
||||
const GLFWwindow* getWindow() const { return window; }
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Public Interface: init and cleanup
|
||||
* @details
|
||||
* These functions can be used by other parts of your program that use this instance,
|
||||
* like a renderer.
|
||||
*/
|
||||
public:
|
||||
/// @{
|
||||
/**
|
||||
* @brief Destroys everything that was initalized in init
|
||||
* @details
|
||||
@ -99,182 +118,91 @@ namespace gz::vk {
|
||||
* -# destroys the window
|
||||
* -# calls glfwTerminate()
|
||||
*/
|
||||
void cleanup();
|
||||
void registerCleanupCallback(std::function<void()> callbackF);
|
||||
|
||||
void registerSwapChainRecreateCallback(std::function<void()> callbackF);
|
||||
/// The frame in the swap chain that is currently drawn to
|
||||
uint32_t currentFrame = 0;
|
||||
|
||||
|
||||
//
|
||||
// SETTINGS
|
||||
//
|
||||
gz::SettingsManager<SettingsTypes> settings;
|
||||
private:
|
||||
std::vector<VkCommandBuffer> commandBuffersToSubmitThisFrame;
|
||||
|
||||
void createWindow();
|
||||
|
||||
std::vector<std::function<void()>> cleanupCallbacks;
|
||||
std::vector<std::function<void()>> scRecreateCallbacks;
|
||||
|
||||
//
|
||||
// INSTANCE
|
||||
//
|
||||
VkInstance instance;
|
||||
/**
|
||||
* @brief Create the vulkan instance
|
||||
* @brief Register vulkan handles used by another object
|
||||
* @details
|
||||
* -# check if validationLayers are available (if enabled)
|
||||
* -# create instance with info
|
||||
* -# check if all extensions required by glfw are available
|
||||
* Use this function to register vulkan handles used by another object.
|
||||
* When a @ref debugLog "validation message" contains one of these handles, the owner can
|
||||
* be determined and added to the message.
|
||||
* This makes the debugging process easier when multiple objects use the same type of vulkan handle.
|
||||
*/
|
||||
void createInstance();
|
||||
static void registerObjectUsingVulkan(const ObjectUsingVulkan& obj);
|
||||
/// @}
|
||||
|
||||
//
|
||||
// PHYSICAL DEVICE
|
||||
//
|
||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||
/// all the properties of the selected physcial device
|
||||
VkPhysicalDeviceProperties phDevProperties;
|
||||
/// all the features that the selected physical device supports
|
||||
PhysicalDeviceFeatures phDevFeatures;
|
||||
/**
|
||||
* @brief Get rhe required physical device features
|
||||
* @name Public Interface: Various utility
|
||||
* @details
|
||||
* The required features are:
|
||||
* - synchronization2
|
||||
* These functions can be used by other parts of your program that use this instance,
|
||||
* like a renderer.
|
||||
*/
|
||||
PhysicalDeviceFeatures getRequiredFeatures() const;
|
||||
/**
|
||||
* @brief Assign the physicalDevice handle to the @ref rateDevice "best rated" GPU
|
||||
* @details
|
||||
* After this method, physicalDevice, phDevProperties and phDevFeatures will be initialized
|
||||
*/
|
||||
void selectPhysicalDevice();
|
||||
/**
|
||||
* @brief Assigns a score to a physical device.
|
||||
* @details
|
||||
* score = GPU_TYPE_FACTOR + VRAM_SIZE (in MB) + SUPPORTED_QUEUES_FACTOR + FEATURES_FACTORS
|
||||
* A GPU is unsuitable and gets score 0 if it does not:
|
||||
* - have the needed queue families
|
||||
* - support all necessary extensions
|
||||
* - have swap chain support
|
||||
*/
|
||||
unsigned int rateDevice(VkPhysicalDevice device);
|
||||
/**
|
||||
* @brief Set valid values for the SettingsManager according to phDevFeatures and phDevProperties
|
||||
* @details
|
||||
* Must be called after selectPhysicalDevice and before createLogicalDevice
|
||||
* Sets valid values for:
|
||||
* - anisotropy_enable
|
||||
* - max_anisotropy
|
||||
*
|
||||
*/
|
||||
void setValidSettings();
|
||||
/**
|
||||
* @brief Find the best of the supported formats
|
||||
* @param candidates Candidate format, from best to worst
|
||||
* @returns The first format from candidates that is supported
|
||||
*/
|
||||
VkFormat findSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
|
||||
public:
|
||||
/// @{
|
||||
const VkDevice& getDevice() const { return device; }
|
||||
const SettingsManager<SettingsTypes>& getSettings() const { return settings; }
|
||||
const VkExtent2D& getScExtent() const { return scExtent; }
|
||||
const std::vector<VkImage>& getScImages() const { return scImages; }
|
||||
const VkFormat& getScImageFormat() const { return scImageFormat; }
|
||||
|
||||
//
|
||||
// QUEUE
|
||||
//
|
||||
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
|
||||
QueueFamilyIndices qFamilyIndices;
|
||||
VkQueue graphicsQ;
|
||||
VkQueue presentQ;
|
||||
// if possible, use dedicated transferQ. if not available, transferQ = graphicsQ
|
||||
VkQueue transferQ;
|
||||
//
|
||||
// LOGICAL DEVICE
|
||||
//
|
||||
VkDevice device;
|
||||
/**
|
||||
* @details
|
||||
* request anisotropic sampling feature
|
||||
* @brief Get the maximum number of frames in flight
|
||||
* @see MAX_FRAMES_IN_FLIGHT
|
||||
*/
|
||||
void createLogicalDevice();
|
||||
const uint32_t getMaxFramesInFlight() const { return MAX_FRAMES_IN_FLIGHT; }
|
||||
/**
|
||||
* @brief Get the frame that is currently in flight
|
||||
* @see currentFrame
|
||||
*/
|
||||
const uint32_t getCurrentFrame() const { return currentFrame; }
|
||||
|
||||
//
|
||||
// SURFACE
|
||||
//
|
||||
VkSurfaceKHR surface;
|
||||
void createSurface();
|
||||
//
|
||||
// SWAP CHAIN
|
||||
//
|
||||
VkSwapchainKHR swapChain;
|
||||
std::vector<VkImage> scImages;
|
||||
std::vector<VkImageView> scImageViews;
|
||||
VkFormat scImageFormat;
|
||||
VkExtent2D scExtent;
|
||||
void submitThisFrame(VkCommandBuffer& cmdBuffer);
|
||||
|
||||
SwapChainSupport querySwapChainSupport(VkPhysicalDevice device);
|
||||
/**
|
||||
* @todo Rate formats if preferred is not available
|
||||
*/
|
||||
VkSurfaceFormatKHR selectSwapChainSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
|
||||
/**
|
||||
* @todo Check settings for preferred mode
|
||||
*/
|
||||
VkPresentModeKHR selectSwapChainPresentMode(const std::vector<VkPresentModeKHR>& availableModes);
|
||||
VkExtent2D selectSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
|
||||
void createSwapChain();
|
||||
void createSwapChainImageViews();
|
||||
void cleanupSwapChain();
|
||||
/**
|
||||
* @brief Recreate the swap chain for the current window size
|
||||
* @brief Copy from srcBuffer to dstBuffer
|
||||
* @details
|
||||
* Does:
|
||||
* -# get new window dimensions
|
||||
* - blocks while dimensions == 0 (minimized)
|
||||
* -# calls cleanupSwapChain
|
||||
* -# calls createSwapChain
|
||||
* -# other stuff
|
||||
* -# calls all callbacks registered with registerSwapChainRecreateCallback
|
||||
* Uses @ref beginSingleTimeCommands() "a single time command buffer" from commandPoolTransfer.
|
||||
*/
|
||||
void recreateSwapChain();
|
||||
//
|
||||
// IMAGE VIEW
|
||||
//
|
||||
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
|
||||
|
||||
/**
|
||||
* @brief Create a 2D imageView with format for image.
|
||||
* @brief Begin a command buffer that is going to be used once
|
||||
* @param commandPool: The command pool from which the buffer should be allocated
|
||||
*/
|
||||
void createImageView(VkFormat format, VkImage& image, VkImageView& imageView, VkImageAspectFlags aspectFlags);
|
||||
//
|
||||
// RENDER PASS
|
||||
//
|
||||
/* VkRenderPass renderPassBegin; */
|
||||
/* VkRenderPass renderPassEnd; */
|
||||
VkCommandBuffer beginSingleTimeCommands(InstanceCommandPool commandPool);
|
||||
/**
|
||||
* @brief Create the render pass
|
||||
* @brief Submit cmdBuffer on the queue and free it afterwards
|
||||
* @param cmdBuffer: Command buffer returned by beginSingleTimeCommands()
|
||||
* @param commandPool: The same pool as passed to beginSingleTimeCommands()
|
||||
*/
|
||||
void endSingleTimeCommands(VkCommandBuffer cmdBuffer, InstanceCommandPool commandPool);
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Public Interface: Vulkan object creation/descruction
|
||||
* @details
|
||||
* The subpass will contain the following attachments
|
||||
* -# color attachment
|
||||
* -# depth stencil attachment
|
||||
* These functions aim at making creation and desctruction of common vulkan objects easier
|
||||
* and can be used by other parts of your program that use this instance,
|
||||
* like a renderer.
|
||||
*/
|
||||
/* void createRenderPassBegin(); */
|
||||
/* void createRenderPassEnd(); */
|
||||
//
|
||||
// DESCRIPTORS
|
||||
//
|
||||
/* VkDescriptorSetLayout descriptorSetLayout; */
|
||||
public:
|
||||
/// @{
|
||||
/**
|
||||
* @brief Create MAX_FRAMES_IN_FLIGHT command buffers from the commandPoolGraphics
|
||||
*/
|
||||
void createCommandBuffers(std::vector<VkCommandBuffer>& commandBuffers);
|
||||
/**
|
||||
* @brief Destroy all command buffers (must be from commandPoolGraphics)
|
||||
*/
|
||||
void destroyCommandBuffers(std::vector<VkCommandBuffer>& commandBuffers);
|
||||
|
||||
/**
|
||||
* @brief Create a descriptor layout with bindings
|
||||
*/
|
||||
void createDescriptorSetLayout(std::vector<VkDescriptorSetLayoutBinding> bindings, VkDescriptorSetLayout& layout);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
//
|
||||
// PIPELINE
|
||||
//
|
||||
|
||||
/* void createGraphicsPipeline(); */
|
||||
VkShaderModule createShaderModule(const std::vector<char>& code);
|
||||
/**
|
||||
* @brief Create a new graphics pipeline
|
||||
* @param vertexShader Path to the SPIR-V vertex shader
|
||||
@ -283,6 +211,8 @@ namespace gz::vk {
|
||||
* @param renderPass The (already created) render pass
|
||||
* @param pipelineLayout Pipeline layout handle to bind
|
||||
* @param pipeline Pipeline handle to bind
|
||||
* @param T the type of Vertex to use
|
||||
*
|
||||
* @details
|
||||
* Create a pipeline with:
|
||||
* - 2 shader stages: vertex and fragment shader
|
||||
@ -292,95 +222,83 @@ namespace gz::vk {
|
||||
* - rasterizer:
|
||||
* - triangles are filled with the colors from the vertex (VK_POLYGON_FILL)
|
||||
* - counter clockwise front face (VK_FRONT_FACE_COUNTER_CLOCKWISE)
|
||||
*
|
||||
*
|
||||
*/
|
||||
template<VertexType T>
|
||||
void createGraphicsPipeline(const std::string& vertexShader, const std::string& fragmentShader, std::vector<VkDescriptorSetLayout>& descriptorSetLayouts, bool useDepthStencil, VkRenderPass& renderPass, Pipeline& pipeline);
|
||||
//
|
||||
// FONT
|
||||
//
|
||||
// TODO
|
||||
/* VkPipeline fontPipeline; */
|
||||
/* VkPipelineLayout fontPipelineLayout; */
|
||||
/* void createFontPipeline(); */
|
||||
//
|
||||
// BUFFERS
|
||||
//
|
||||
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory, VkSharingMode sharingMode=VK_SHARING_MODE_EXCLUSIVE, std::vector<uint32_t>* qFamiliesWithAccess=nullptr);
|
||||
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
|
||||
|
||||
VkShaderModule createShaderModule(const std::vector<char>& code);
|
||||
|
||||
/**
|
||||
* @brief Begin a command buffer that is going to be used once
|
||||
* @param commandPool: The command pool from which the buffer should be allocated
|
||||
* @brief Allocate memory, create a buffer and bind buffer to memory
|
||||
* @param size The size of the buffer
|
||||
* @param buffer The (null) handle to the buffer
|
||||
* @param bufferMemory Reference to an (uninitialized) MemoryInfo struct. It will be valid when the function returns
|
||||
* @param properties Properties that the buffers memory needs to satisfy
|
||||
*/
|
||||
VkCommandBuffer beginSingleTimeCommands(VkCommandPool commandPool);
|
||||
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, MemoryInfo& bufferMemory, VkSharingMode sharingMode=VK_SHARING_MODE_EXCLUSIVE, std::vector<uint32_t>* qFamiliesWithAccess=nullptr);
|
||||
/**
|
||||
* @brief Submit cmdBuffer on the queue and free it afterwards
|
||||
* @param cmdBuffer: Command buffer returned by beginSingleTimeCommands()
|
||||
* @param q: The queue belonging to the commandPool parameter from beginSingleTimeCommands()
|
||||
* @brief Destroy buffer and free memory
|
||||
*/
|
||||
void endSingleTimeCommands(VkCommandBuffer cmdBuffer, VkCommandPool commandPool, VkQueue q);
|
||||
/**
|
||||
* @brief Copy from srcBuffer to dstBuffer
|
||||
*/
|
||||
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
|
||||
//
|
||||
// VERTEX BUFFER
|
||||
//
|
||||
void destroyBuffer(VkBuffer& buffer, MemoryInfo& bufferMemory);
|
||||
|
||||
/**
|
||||
* @brief Create a vertex buffer
|
||||
* @param vertexCount Number of vertices the buffer should contain
|
||||
* @todo Basically the same as createIndexBuffer
|
||||
* @param vertexBuffer The (null) handle to the buffer
|
||||
* @param vertexBufferMemory Reference to an (uninitialized) MemoryInfo struct. It will be valid when the function returns
|
||||
* @details
|
||||
* The function is instantiated for Vertex2D and Vertex3D
|
||||
*/
|
||||
template<VertexType VertexT>
|
||||
void createVertexBuffer(size_t vertexCount, VkBuffer& vertexBuffer, VkDeviceMemory& vertexBufferMemory, VkDeviceSize& vertexBufferSize);
|
||||
//
|
||||
// INDEX BUFFER
|
||||
//
|
||||
void createVertexBuffer(size_t vertexCount, VkBuffer& vertexBuffer, MemoryInfo& vertexBufferMemory, VkDeviceSize& vertexBufferSize);
|
||||
|
||||
/**
|
||||
* @brief Create an index buffer
|
||||
* @param indexCount Number of indices the buffer should contain
|
||||
* @param indexBuffer The (null) handle to the buffer
|
||||
* @param indexBufferMemory Reference to an (uninitialized) MemoryInfo struct. It will be valid when the function returns
|
||||
* @details
|
||||
* The function is instantiated for uint16_t and uint32_t
|
||||
*/
|
||||
template<SupportedIndexType T>
|
||||
void createIndexBuffer(size_t indexCount, VkBuffer& indexBuffer, VkDeviceMemory& indexBufferMemory, VkDeviceSize& indexBufferSize);
|
||||
//
|
||||
// UNIFORM BUFFER
|
||||
//
|
||||
void createIndexBuffer(size_t indexCount, VkBuffer& indexBuffer, MemoryInfo& indexBufferMemory, VkDeviceSize& indexBufferSize);
|
||||
|
||||
/**
|
||||
* @brief Create MAX_FRAMES_IN_FLIGHT uniform buffers
|
||||
*/
|
||||
template<typename T>
|
||||
void createUniformBuffers(std::vector<VkBuffer>& uniformBuffers, std::vector<VkDeviceMemory>& uniformBuffersMemory);
|
||||
/* void createUniformBuffers(); */
|
||||
//
|
||||
// FRAMEBUFFERS
|
||||
//
|
||||
void createUniformBuffers(std::vector<VkBuffer>& uniformBuffers, std::vector<MemoryInfo>& uniformBuffersMemory);
|
||||
|
||||
/**
|
||||
* @brief Create as many framebuffers as the swap chain has images, with the extent of the swap chain
|
||||
*/
|
||||
void createFramebuffers(std::vector<VkFramebuffer>& framebuffers, std::vector<VkImageView>& imageViews, VkRenderPass& renderPass);
|
||||
/**
|
||||
* @brief Destroy the framebuffers
|
||||
*/
|
||||
void destroyFramebuffers(std::vector<VkFramebuffer>& framebuffers);
|
||||
void createFramebuffers(std::vector<VkFramebuffer>& framebuffers, std::vector<VkImageView>& imageViews, VkRenderPass& renderPass);
|
||||
bool frameBufferResized = false;
|
||||
static void frameBufferResizedCallback(GLFWwindow* window, int width, int height);
|
||||
//
|
||||
// COMMAND POOL
|
||||
//
|
||||
VkCommandPool commandPoolGraphics;
|
||||
VkCommandPool commandPoolTransfer;
|
||||
void createCommandPools();
|
||||
//
|
||||
// COMMAND BUFFER
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief Create MAX_FRAMES_IN_FLIGHT command buffers from the commandPoolGraphics
|
||||
* @brief Create a texture sampler
|
||||
* @todo add options and documentation
|
||||
*/
|
||||
void createCommandBuffers(std::vector<VkCommandBuffer>& commandBuffers);
|
||||
void createTextureSampler(VkSampler& sampler);
|
||||
|
||||
/**
|
||||
* @brief Destroy all command buffers (must be from commandPoolGraphics)
|
||||
* @name Public Interface: Image utility
|
||||
* @details
|
||||
* These functions can be used by other parts of your program that use this instance,
|
||||
* like a renderer.
|
||||
*/
|
||||
void destroyCommandBuffers(std::vector<VkCommandBuffer>& commandBuffers);
|
||||
std::vector<VkCommandBuffer> commandBuffersBegin;
|
||||
std::vector<VkCommandBuffer> commandBuffersEnd;
|
||||
//
|
||||
// IMAGE UTILITY
|
||||
//
|
||||
/// @{
|
||||
/**
|
||||
* @brief Create the image, allocate the imageMemory and bind the image to it
|
||||
*/
|
||||
void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkImage& image, VkDeviceMemory& imageMemory);
|
||||
/**
|
||||
* @brief Create a 2D imageView with format for image.
|
||||
*/
|
||||
void createImageView(VkFormat format, VkImage& image, VkImageView& imageView, VkImageAspectFlags aspectFlags);
|
||||
void copyBufferToImage(VkBuffer buffer, VkImage image, int32_t offsetX, int32_t offsetY, uint32_t width, uint32_t height);
|
||||
/**
|
||||
* @todo make a version using vkCmdResolveImage for multisampled images
|
||||
@ -416,69 +334,15 @@ namespace gz::vk {
|
||||
* @throws VkUserError if the transition is not supported.
|
||||
*/
|
||||
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, VkCommandBuffer* cmdBuffer=nullptr);
|
||||
|
||||
//
|
||||
// DEPTH
|
||||
//
|
||||
/* VkImage depthImage; */
|
||||
/* VkDeviceMemory depthImageMemory; */
|
||||
/* VkImageView depthImageView; */
|
||||
VkFormat findDepthFormat();
|
||||
/* void createDepthImageAndView(); */
|
||||
//
|
||||
// TEXTURES
|
||||
//
|
||||
/* VkImage textureImage; */
|
||||
/* VkDeviceMemory textureImageMemory; */
|
||||
/* VkImageView textureImageView; */
|
||||
/* VkSampler textureSampler; */
|
||||
/// Load textures/image.png
|
||||
/* void createTextureImageAndView(); */
|
||||
void createTextureSampler(VkSampler& sampler);
|
||||
|
||||
//
|
||||
// SYNCHRONIZATION
|
||||
//
|
||||
std::vector<VkSemaphore> imageAvailableSemaphores;
|
||||
std::vector<VkSemaphore> renderFinishedSemaphores;
|
||||
std::vector<VkFence> inFlightFences;
|
||||
void createSyncObjects();
|
||||
//
|
||||
// SHADERS
|
||||
//
|
||||
static std::vector<char> readFile(const std::string& filename);
|
||||
//
|
||||
// MODELS
|
||||
//
|
||||
void loadModel();
|
||||
VerticesAndIndices<uint32_t> model;
|
||||
//
|
||||
// DEBUG
|
||||
//
|
||||
void setupDebugMessenger();
|
||||
void cleanupDebugMessenger();
|
||||
VkDebugUtilsMessengerEXT debugMessenger;
|
||||
static gz::Log vLog;
|
||||
public:
|
||||
//
|
||||
// UTILITY
|
||||
//
|
||||
/**
|
||||
* @name Debugging
|
||||
*/
|
||||
/// @{
|
||||
/**
|
||||
* @name Handle ownership
|
||||
* @brief Retrieve the owner of a vulkan handle
|
||||
* @see ObjectUsingVulkan
|
||||
*/
|
||||
/// @{
|
||||
static std::vector<ObjectUsingVulkan> objectsUsingVulkan;
|
||||
static void registerObjectUsingVulkan(const ObjectUsingVulkan& obj);
|
||||
static void getHandleOwnerString(std::string_view message);
|
||||
static std::string handleOwnerString;
|
||||
static bool lastColorWhite;
|
||||
/// @}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @name Debugging (validation messages)
|
||||
*/
|
||||
public:
|
||||
/// @{
|
||||
/**
|
||||
* @brief Log messages from validation layers with the Apps logger
|
||||
* @details
|
||||
@ -486,7 +350,7 @@ namespace gz::vk {
|
||||
* - Validation and performace messages usually have a bracket containing a VUID,
|
||||
* these brackets are printed in yellow/red when its a warning/error.
|
||||
* - Handles printed by the validation layer are checked with objectsUsingVulkan, if found
|
||||
* the owner of the handle is added to the message @see registerObjectUsingVulkan, ObjectUsingVulkan
|
||||
* the owner of the handle is added to the message @see registerObjectUsingVulkan(), ObjectUsingVulkan
|
||||
* - Different message sources (layer, shader, general...) get a prefix with a different color
|
||||
*/
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugLog(
|
||||
@ -496,29 +360,293 @@ namespace gz::vk {
|
||||
void* pUserData);
|
||||
/// @}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @name Settings
|
||||
*/
|
||||
/// @{
|
||||
gz::SettingsManager<SettingsTypes> settings;
|
||||
/**
|
||||
* @brief Set valid values for the SettingsManager according to phDevFeatures and phDevProperties
|
||||
* @details
|
||||
* Must be called after selectPhysicalDevice() and before createLogicalDevice()
|
||||
* Sets valid values for:
|
||||
* - anisotropy_enable (bool) [features.samplerAnisotropy]
|
||||
* - max_anisotropy (float) [1-limits.maxSamplerAnisotropy]
|
||||
* - max_frames_in_flight (uint32_t) [1-4]
|
||||
*
|
||||
*/
|
||||
void setValidSettings();
|
||||
/**
|
||||
* @brief The maximum number of frames that can be ready for presentation
|
||||
* @details
|
||||
* A higher number can lead to more stable frame rates, but also increases latency.
|
||||
*
|
||||
* This variable is assigned from setting "max_frames_in_flight".
|
||||
* @warning
|
||||
* Do not use the setting from the settings manager:
|
||||
* A lot of resources depend on this variable and if it gets changed at runtime, the program would crash.
|
||||
* Always use this variable (or the @ref getMaxFramesInFlight() "getter").
|
||||
* Changes to max_frames_in_flight will take effect upon restart.
|
||||
*/
|
||||
uint32_t MAX_FRAMES_IN_FLIGHT;
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Window
|
||||
*/
|
||||
/// @{
|
||||
GLFWwindow* window;
|
||||
void createWindow();
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Framebuffers
|
||||
*/
|
||||
/// @{
|
||||
bool frameBufferResized = false;
|
||||
static void frameBufferResizedCallback(GLFWwindow* window, int width, int height);
|
||||
|
||||
/**
|
||||
* @brief The frame that is currently in flight
|
||||
* @details
|
||||
* The value is between 0 and MAX_FRAMES_IN_FLIGHT - 1.
|
||||
* It specifies which command buffer or uniform buffer to use for drawing the current frame,
|
||||
* it is not the image index for the current @ref scImages "swap chain image".
|
||||
*/
|
||||
uint32_t currentFrame = 0;
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Cleanup
|
||||
*/
|
||||
/// @{
|
||||
std::vector<std::function<void()>> cleanupCallbacks;
|
||||
std::vector<std::function<void()>> scRecreateCallbacks;
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Instance
|
||||
*/
|
||||
/// @{
|
||||
VkInstance instance;
|
||||
/**
|
||||
* @brief Create the vulkan instance
|
||||
* @details
|
||||
* -# check if validationLayers are available (if enabled)
|
||||
* -# create instance with info
|
||||
* -# check if all extensions required by glfw are available
|
||||
*/
|
||||
void createInstance();
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Physical device
|
||||
*/
|
||||
/// @{
|
||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||
/// all the properties of the selected physcial device
|
||||
VkPhysicalDeviceProperties phDevProperties;
|
||||
/// all the features that the selected physical device supports
|
||||
PhysicalDeviceFeatures phDevFeatures;
|
||||
/**
|
||||
* @brief Get the required physical device features
|
||||
* @details
|
||||
* The required features are:
|
||||
* - synchronization2
|
||||
*/
|
||||
PhysicalDeviceFeatures getRequiredFeatures() const;
|
||||
/**
|
||||
* @brief Assign the physicalDevice handle to the @ref rateDevice "best rated" GPU
|
||||
* @details
|
||||
* After this method, physicalDevice, phDevProperties and phDevFeatures will be initialized
|
||||
*/
|
||||
void selectPhysicalDevice();
|
||||
/**
|
||||
* @brief Assigns a score to a physical device.
|
||||
* @details
|
||||
* score = GPU_TYPE_FACTOR + VRAM_SIZE (in MB) + SUPPORTED_QUEUES_FACTOR + FEATURES_FACTORS
|
||||
* A GPU is unsuitable and gets score 0 if it does not:
|
||||
* - have the needed queue families
|
||||
* - support all necessary extensions
|
||||
* - have swap chain support
|
||||
*/
|
||||
unsigned int rateDevice(VkPhysicalDevice device);
|
||||
/**
|
||||
* @brief Find the best of the supported formats
|
||||
* @param candidates Candidate format, from best to worst
|
||||
* @returns The first format from candidates that is supported
|
||||
*/
|
||||
VkFormat findSupportedFormat(const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Memory management
|
||||
*/
|
||||
/// @{
|
||||
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
|
||||
VulkanAllocator allocator;
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Queue
|
||||
*/
|
||||
/// @{
|
||||
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
|
||||
QueueFamilyIndices qFamilyIndices;
|
||||
VkQueue graphicsQ;
|
||||
VkQueue presentQ;
|
||||
// if possible, use dedicated transferQ. if not available, transferQ = graphicsQ
|
||||
VkQueue transferQ;
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Logical device
|
||||
*/
|
||||
/// @{
|
||||
VkDevice device;
|
||||
/**
|
||||
* @details
|
||||
* request anisotropic sampling feature
|
||||
*/
|
||||
void createLogicalDevice();
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Surface
|
||||
*/
|
||||
/// @{
|
||||
VkSurfaceKHR surface;
|
||||
void createSurface();
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Swap chain
|
||||
*/
|
||||
/// @{
|
||||
VkSwapchainKHR swapChain;
|
||||
std::vector<VkImage> scImages;
|
||||
std::vector<VkImageView> scImageViews;
|
||||
VkFormat scImageFormat;
|
||||
VkExtent2D scExtent;
|
||||
|
||||
SwapChainSupport querySwapChainSupport(VkPhysicalDevice device);
|
||||
/**
|
||||
* @todo Rate formats if preferred is not available
|
||||
*/
|
||||
VkSurfaceFormatKHR selectSwapChainSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats);
|
||||
/**
|
||||
* @todo Check settings for preferred mode
|
||||
*/
|
||||
VkPresentModeKHR selectSwapChainPresentMode(const std::vector<VkPresentModeKHR>& availableModes);
|
||||
VkExtent2D selectSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
|
||||
void createSwapChain();
|
||||
void createSwapChainImageViews();
|
||||
void cleanupSwapChain();
|
||||
/**
|
||||
* @brief Recreate the swap chain for the current window size
|
||||
* @details
|
||||
* Does:
|
||||
* -# get new window dimensions
|
||||
* - blocks while dimensions == 0 (minimized)
|
||||
* -# calls cleanupSwapChain
|
||||
* -# calls createSwapChain
|
||||
* -# other stuff
|
||||
* -# calls all callbacks registered with registerSwapChainRecreateCallback
|
||||
*/
|
||||
void recreateSwapChain();
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Command pools
|
||||
*/
|
||||
/// @{
|
||||
VkCommandPool commandPoolGraphics;
|
||||
VkCommandPool commandPoolTransfer;
|
||||
void createCommandPools();
|
||||
/// @}
|
||||
/**
|
||||
* @name Command buffers
|
||||
*/
|
||||
/// @{
|
||||
std::vector<VkCommandBuffer> commandBuffersBegin;
|
||||
std::vector<VkCommandBuffer> commandBuffersEnd;
|
||||
/**
|
||||
* @brief All command buffers to submit on graphics queue for the current frame
|
||||
* @details
|
||||
* Use submitThisFrame() to submit a command buffer
|
||||
*/
|
||||
std::vector<VkCommandBuffer> commandBuffersToSubmitThisFrame;
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Synchronization
|
||||
*/
|
||||
/// @{
|
||||
std::vector<VkSemaphore> imageAvailableSemaphores;
|
||||
std::vector<VkSemaphore> renderFinishedSemaphores;
|
||||
std::vector<VkFence> inFlightFences;
|
||||
void createSyncObjects();
|
||||
/// @}
|
||||
|
||||
|
||||
/**
|
||||
* @name Shaders
|
||||
*/
|
||||
/// @{
|
||||
/**
|
||||
* @brief Load a binary file into vector of bytes
|
||||
* @todo Move to more generic constant, does not need to be member function
|
||||
*/
|
||||
static std::vector<char> readFile(const std::string& filename);
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Models
|
||||
*/
|
||||
/// @{
|
||||
void loadModel(VerticesAndIndices<uint32_t>& model);
|
||||
/// @}
|
||||
|
||||
|
||||
/**
|
||||
* @name Utility
|
||||
*/
|
||||
/// @{
|
||||
template<typename T, typename... Args>
|
||||
VkResult runVkResultFunction(const char* name, Args&&... args) {
|
||||
auto f = reinterpret_cast<T>(vkGetInstanceProcAddr(instance, name));
|
||||
if (f == nullptr) {
|
||||
vLog.error("getVkFunction: Could not get function:", name);
|
||||
throw std::runtime_error("getVkFunction: Could not get function.");
|
||||
}
|
||||
else {
|
||||
return f(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
VkResult runVkResultFunction(const char* name, Args&&... args);
|
||||
template<typename T, typename... Args>
|
||||
void runVkVoidFunction(const char* name, Args&&... args) {
|
||||
auto f = reinterpret_cast<T>(vkGetInstanceProcAddr(instance, name));
|
||||
if (f == nullptr) {
|
||||
vLog.error("getVkFunction: Could not get function:", name);
|
||||
throw std::runtime_error("getVkFunction: Could not get function.");
|
||||
}
|
||||
else {
|
||||
f(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
void runVkVoidFunction(const char* name, Args&&... args);
|
||||
|
||||
/**
|
||||
* @name Debugging: (log and validation debug messenger)
|
||||
*/
|
||||
/// @{
|
||||
void setupDebugMessenger();
|
||||
void cleanupDebugMessenger();
|
||||
VkDebugUtilsMessengerEXT debugMessenger;
|
||||
static gz::Log vLog;
|
||||
/// @} /// @}
|
||||
|
||||
/**
|
||||
* @name Debugging: (handle ownership)
|
||||
*/
|
||||
/// @{
|
||||
static std::vector<ObjectUsingVulkan> objectsUsingVulkan;
|
||||
/**
|
||||
* @brief Search for handles in message and get their owners
|
||||
* @details
|
||||
* Searches for handles (hex numbers) in message and sets handleOwnerString.\n
|
||||
* If message contains no handle, handleOwnerString will be empty.
|
||||
* If message contains at least one handle, handleOwnerString will be:
|
||||
* `Handle Ownerships: [ <handle> - <owner>, ...]`
|
||||
*/
|
||||
static void getHandleOwnerString(std::string_view message);
|
||||
static std::string handleOwnerString;
|
||||
/// Used for alternating the color of validation messages between grey and white
|
||||
static bool lastColorWhite;
|
||||
/// @}
|
||||
|
||||
}; // VulkanInstance
|
||||
|
||||
//
|
||||
@ -528,7 +656,7 @@ namespace gz::vk {
|
||||
// UNIFORM BUFFERS
|
||||
//
|
||||
template<typename T>
|
||||
void VulkanInstance::createUniformBuffers(std::vector<VkBuffer>& uniformBuffers, std::vector<VkDeviceMemory>& uniformBuffersMemory) {
|
||||
void VulkanInstance::createUniformBuffers(std::vector<VkBuffer>& uniformBuffers, std::vector<MemoryInfo>& uniformBuffersMemory) {
|
||||
VkDeviceSize bufferSize = sizeof(T);
|
||||
|
||||
uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
|
||||
@ -539,9 +667,35 @@ namespace gz::vk {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// UTILITY
|
||||
//
|
||||
template<typename T, typename... Args>
|
||||
VkResult VulkanInstance::runVkResultFunction(const char* name, Args&&... args) {
|
||||
auto f = reinterpret_cast<T>(vkGetInstanceProcAddr(instance, name));
|
||||
if (f == nullptr) {
|
||||
vLog.error("getVkFunction: Could not get function:", name);
|
||||
throw std::runtime_error("getVkFunction: Could not get function.");
|
||||
}
|
||||
else {
|
||||
return f(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void VulkanInstance::runVkVoidFunction(const char* name, Args&&... args) {
|
||||
auto f = reinterpret_cast<T>(vkGetInstanceProcAddr(instance, name));
|
||||
if (f == nullptr) {
|
||||
vLog.error("getVkFunction: Could not get function:", name);
|
||||
throw std::runtime_error("getVkFunction: Could not get function.");
|
||||
}
|
||||
else {
|
||||
f(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* @file Creating a vulkan instance
|
||||
* @todo Write/get allocator for buffers
|
||||
* @file Vulkan instance
|
||||
*/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user