mirror of
https://github.com/barkeser2002/flower.git
synced 2026-09-25 16:36:15 +03:00
402 lines
15 KiB
C++
402 lines
15 KiB
C++
#pragma once
|
|
|
|
#include <vulkan/vulkan.h>
|
|
#include <vk_mem_alloc.h>
|
|
|
|
#include <util/util.h>
|
|
#include <util/lru.h>
|
|
|
|
#include "sampler_cache.h"
|
|
#include "shader_cache.h"
|
|
#include "descriptor.h"
|
|
#include "swapchain.h"
|
|
#include "async_upload.h"
|
|
#include "gpu_asset.h"
|
|
#include "render_texture_pool.h"
|
|
#include "pass.h"
|
|
#include "dynamic_uniform_buffer.h"
|
|
#include "ssbo_buffers.h"
|
|
|
|
namespace engine
|
|
{
|
|
|
|
|
|
enum class EBuiltinEngineAsset
|
|
{
|
|
Texture_Min,
|
|
Texture_White, // 255, 255, 255, 255
|
|
Texture_Grey, // 128, 128, 128, 255
|
|
Texture_Black, // 0, 0, 0, 255
|
|
Texture_Translucent, // 0, 0, 0, 0
|
|
Texture_Normal, // 125, 130, 255, 0
|
|
Texture_Specular, // 255, 255, 0, 0 .r AO, .g roughness, .b metal
|
|
Texture_CloudWeather,
|
|
Texture_CurlNoise,
|
|
Texture_Noise,
|
|
Texture_Sky3d,
|
|
Texture_SkinLut,
|
|
Texture_SkinLutShadow,
|
|
Texture_Max,
|
|
|
|
StaticMesh_Min,
|
|
StaticMesh_Box, //
|
|
StaticMesh_Sphere, //
|
|
StaticMesh_Max,
|
|
};
|
|
|
|
class VulkanContext final : public IRuntimeModule
|
|
{
|
|
public:
|
|
VulkanContext(Engine* engine) : IRuntimeModule(engine) { }
|
|
~VulkanContext() = default;
|
|
|
|
virtual void registerCheck(Engine* engine) override;
|
|
virtual bool init() override;
|
|
virtual bool tick(const RuntimeModuleTickData& tickData) override;
|
|
virtual void release() override;
|
|
|
|
struct GPUCommandPool
|
|
{
|
|
VkQueue queue = VK_NULL_HANDLE;
|
|
VkCommandPool pool = VK_NULL_HANDLE;
|
|
};
|
|
|
|
void setResourceName(VkObjectType objectType, uint64_t handle, const char* name) const;
|
|
void setPerfMarkerBegin(VkCommandBuffer cmdBuf, const char* name, const math::vec4& color) const;
|
|
void setPerfMarkerEnd(VkCommandBuffer cmdBuf) const;
|
|
|
|
const VkPhysicalDeviceMemoryProperties& getPhysicalDeviceMemoryProperties() const { return m_memoryProperties; }
|
|
const VkPhysicalDeviceDescriptorIndexingPropertiesEXT& getPhysicalDeviceDescriptorIndexingProperties() const { return m_descriptorIndexingProperties; }
|
|
const VkPhysicalDeviceProperties& getPhysicalDeviceProperties() const { return m_deviceProperties; }
|
|
|
|
VkDevice getDevice() const { return m_device; }
|
|
VkPhysicalDevice getGPU() const { return m_gpu; }
|
|
VmaAllocator getVMA() const { return m_vma; }
|
|
VkInstance getInstance() const { return m_instance; }
|
|
VkSurfaceKHR getSurface() const { return m_surface; }
|
|
|
|
// Major graphics queue with 1.0 priority.
|
|
VkQueue getMajorGraphicsQueue() const { return m_majorGraphicsPool.queue; }
|
|
|
|
// Major graphics command pool with 1.0 priority.
|
|
VkCommandPool getMajorGraphicsCommandPool() const { return m_majorGraphicsPool.pool; }
|
|
|
|
// Create command buffer from major graphics queue and command pool.
|
|
[[nodiscard]] VkCommandBuffer createMajorGraphicsCommandBuffer();
|
|
void freeMajorGraphicsCommandBuffer(VkCommandBuffer cmd);
|
|
|
|
// Second major graphics queue with 0.8 priority.
|
|
VkQueue getSecondMajorGraphicsQueue() const { return m_secondMajorGraphicsPool.queue; }
|
|
|
|
// Second major graphics command pool with 0.8 priority.
|
|
VkCommandPool getSecondMajorGraphicsCommandPool() const { return m_secondMajorGraphicsPool.pool; }
|
|
|
|
// Major compute queue with priority 0.8.
|
|
VkQueue getMajorComputeQueue() const { return m_majorComputePool.queue; }
|
|
|
|
// Major compute command pool with priority 0.8.
|
|
VkCommandPool getMajorComputeCommandPool() const { return m_majorComputePool.pool; }
|
|
|
|
// Normal copy command pools with 0.5 priority.
|
|
const auto& getNormalCopyCommandPools() const { return m_copyPools; }
|
|
|
|
// Normal compute command pools with 0.5 priority.
|
|
const auto& getNormalComputeCommandPools() const { return m_computePools; }
|
|
|
|
// Normal graphics command pools with 0.5 priority.
|
|
const auto& getNormalGraphicsCommandPools() const { return m_graphicsPools; }
|
|
|
|
const auto& getGPUQueuesInfo() const { return m_queues; }
|
|
uint32_t getGraphiscFamily() const { return m_queues.graphicsFamily; }
|
|
uint32_t getComputeFamily() const { return m_queues.computeFamily; }
|
|
uint32_t getCopyFamily() const { return m_queues.copyFamily; }
|
|
|
|
void executeImmediately(VkCommandPool commandPool, VkQueue queue, std::function<void(VkCommandBuffer cb)>&& func) const;
|
|
void executeImmediatelyMajorGraphics(std::function<void(VkCommandBuffer cb)>&& func) const;
|
|
|
|
SamplerCache& getSamplerCache() { return m_samplerCache; }
|
|
ShaderCache& getShaderCache() { return m_shaderCache; }
|
|
|
|
// Context owned bindless sampler.
|
|
BindlessSampler& getBindlessSampler() { return m_bindlessSampler; }
|
|
const BindlessSampler& getBindlessSampler() const { return m_bindlessSampler; }
|
|
VkDescriptorSet getBindlessSamplerSet() const { return m_bindlessSampler.getSet(); }
|
|
VkDescriptorSetLayout getBindlessSamplerSetLayout() const { return m_bindlessSampler.getSetLayout(); }
|
|
|
|
// Context owned bindless texture.
|
|
BindlessTexture& getBindlessTexture() { return m_bindlessTexture; }
|
|
const BindlessTexture& getBindlessTexture() const { return m_bindlessTexture; }
|
|
VkDescriptorSet getBindlessTextureSet() const { return m_bindlessTexture.getSet(); }
|
|
VkDescriptorSetLayout getBindlessTextureSetLayout() const { return m_bindlessTexture.getSetLayout(); }
|
|
|
|
|
|
// Context owned bindless texture.
|
|
BindlessStorageBuffer& getBindlessSSBOs() { return m_bindlessStorageBuffer; }
|
|
const BindlessStorageBuffer& getBindlessSSBOs() const { return m_bindlessStorageBuffer; }
|
|
VkDescriptorSet getBindlessSSBOSet() const { return m_bindlessStorageBuffer.getSet(); }
|
|
VkDescriptorSetLayout getBindlessSSBOSetLayout() const { return m_bindlessStorageBuffer.getSetLayout(); }
|
|
|
|
const auto& getSwapchain() const { return m_swapchain; }
|
|
|
|
GLFWwindow* getWindow() const { return m_window; }
|
|
|
|
VkFormat getSupportedBestDepthOnlyFormat() const { return m_cacheSupportDepthOnlyFormat; }
|
|
VkFormat getSupportedBestDepthStencilFormat() const { return m_cacheSupportDepthStencilFormat; }
|
|
|
|
// Swapchain using back buffer format type.
|
|
const EBackBufferFormat& getBackbufferFormatType() const { return m_backbufferFormat; }
|
|
uint32_t getBackBufferCount() const { return m_swapchain.getBackbufferCount(); }
|
|
|
|
DescriptorLayoutCache& getDescriptorLayoutCache() { return m_descriptorLayoutCache; }
|
|
const DescriptorLayoutCache& getDescriptorLayoutCache() const { return m_descriptorLayoutCache; }
|
|
|
|
DescriptorFactory descriptorFactoryBegin();
|
|
VkPipelineLayout createPipelineLayout(const VkPipelineLayoutCreateInfo& info);
|
|
|
|
void recreateSwapChain();
|
|
|
|
MulticastDelegate<> onBeforeSwapchainRecreate;
|
|
MulticastDelegate<> onAfterSwapchainRecreate;
|
|
|
|
uint32_t acquireNextPresentImage();
|
|
void present();
|
|
|
|
// Submit to major graphics queue with reset sync fence.
|
|
void submit(uint32_t count, VkSubmitInfo* infos);
|
|
|
|
// Submit to major graphics queue with special fence.
|
|
void submit(uint32_t count, VkSubmitInfo* infos, VkFence fence);
|
|
|
|
// Submit to major graphics queue with special fence.
|
|
void submit(uint32_t count, const RHISubmitInfo* infos, VkFence fence);
|
|
|
|
// Submit to major graphics queue without reset sync fence.
|
|
void submitNoFence(uint32_t count, VkSubmitInfo* infos);
|
|
|
|
// Just reset major graphics queue sync fence.
|
|
void resetFence();
|
|
|
|
VkSemaphore getCurrentFrameWaitSemaphore() const { return m_presentContext.semaphoresImageAvailable[m_presentContext.currentFrame]; }
|
|
VkSemaphore getCurrentFrameFinishSemaphore() const { return m_presentContext.semaphoresRenderFinished[m_presentContext.currentFrame]; }
|
|
|
|
void waitDeviceIdle() const;
|
|
|
|
AsyncUploaderManager& getAsyncUploader() { return *m_uploader; }
|
|
|
|
|
|
|
|
static UUID getBuiltEngineAssetUUID(EBuiltinEngineAsset type);
|
|
bool isEngineAssetExist(const UUID& uuid) { return m_engineAssets.contains(uuid); }
|
|
bool isLRUAssetExist(const UUID& uuid) { return m_lru->contain(uuid); }
|
|
void insertEngineAsset(const UUID& uuid, std::shared_ptr<LRUAssetInterface> asset);
|
|
void insertLRUAsset(const UUID& uuid, std::shared_ptr<LRUAssetInterface> asset);
|
|
enum class EContextState
|
|
{
|
|
init,
|
|
ticking,
|
|
release,
|
|
};
|
|
|
|
// Context start to kill all? Will set true after call release.
|
|
EContextState getState() const { return m_state; }
|
|
bool isReleaseing() const { return m_state == EContextState::release; }
|
|
|
|
std::shared_ptr<GPUImageAsset> getEngineTextureWhite() const { return std::dynamic_pointer_cast<GPUImageAsset>(getEngineAsset(EBuiltinEngineAsset::Texture_White)); }
|
|
std::shared_ptr<GPUImageAsset> getEngineTextureNormal() const { return std::dynamic_pointer_cast<GPUImageAsset>(getEngineAsset(EBuiltinEngineAsset::Texture_Normal)); }
|
|
std::shared_ptr<GPUImageAsset> getEngineTextureSkinLut() const { return std::dynamic_pointer_cast<GPUImageAsset>(getEngineAsset(EBuiltinEngineAsset::Texture_SkinLut)); }
|
|
std::shared_ptr<GPUImageAsset> getEngineTextureSkinLutShadow() const { return std::dynamic_pointer_cast<GPUImageAsset>(getEngineAsset(EBuiltinEngineAsset::Texture_SkinLutShadow)); }
|
|
std::shared_ptr<GPUImageAsset> getEngineTextureSpecular() const { return std::dynamic_pointer_cast<GPUImageAsset>(getEngineAsset(EBuiltinEngineAsset::Texture_Specular)); }
|
|
std::shared_ptr<GPUImageAsset> getEngineTextureTranslucent() const { return std::dynamic_pointer_cast<GPUImageAsset>(getEngineAsset(EBuiltinEngineAsset::Texture_Translucent)); }
|
|
std::shared_ptr<GPUStaticMeshAsset> getEngineStaticMeshBox() const { return std::dynamic_pointer_cast<GPUStaticMeshAsset>(getEngineAsset(EBuiltinEngineAsset::StaticMesh_Box)); }
|
|
std::shared_ptr<LRUAssetInterface> getEngineAsset(EBuiltinEngineAsset asset) const;
|
|
std::shared_ptr<LRUAssetInterface> getEngineAsset(const UUID& uuid) const;
|
|
void insertGPUAsset(const UUID& uuid, std::shared_ptr<LRUAssetInterface> asset){ m_lru->insert(uuid, asset); }
|
|
|
|
const StaticMeshRenderBounds& getEngineMeshRenderBounds(const UUID& uuid) const { return m_engineMeshBounds.at(uuid); }
|
|
|
|
|
|
std::shared_ptr<GPUStaticMeshAsset> getOrCreateStaticMeshAsset(const UUID& uuid);
|
|
std::shared_ptr<GPUImageAsset> getOrCreateTextureAsset(const UUID& uuid);
|
|
const auto& getLRU() const { return m_lru; }
|
|
|
|
const auto& getPasses() const { return *m_passCollector; }
|
|
auto& getPasses() { return *m_passCollector; }
|
|
|
|
const auto& getRenderTargetPools() const { return *m_rtPool; }
|
|
auto& getRenderTargetPools() { return *m_rtPool; }
|
|
|
|
const auto& getGraphicsCardState() const { return m_graphicsSupportStates; }
|
|
|
|
const auto& getBufferParameters() const { return *m_bufferParameters; }
|
|
auto& getBufferParameters() { return *m_bufferParameters; }
|
|
|
|
const auto& getDynamicUniformBuffers() const { return *m_dynamicUniformBuffer; }
|
|
auto& getDynamicUniformBuffers() { return *m_dynamicUniformBuffer; }
|
|
|
|
const auto& getPhysicalDeviceAccelerationStructurePropertiesKHR() const { return m_accelerationStructureProperties; }
|
|
|
|
void pushDescriptorSet(
|
|
VkCommandBuffer commandBuffer,
|
|
VkPipelineBindPoint pipelineBindPoint,
|
|
VkPipelineLayout layout,
|
|
uint32_t set,
|
|
uint32_t descriptorWriteCount,
|
|
const VkWriteDescriptorSet* pDescriptorWrites);
|
|
|
|
void pushGpuResourceAsPendingKill(std::shared_ptr<GpuResource> asset);
|
|
private:
|
|
void initInstance();
|
|
void destroyInstance();
|
|
|
|
void selectGPU();
|
|
void queryGPUInfo();
|
|
|
|
void initDeviceAndQueue();
|
|
void destroyDevice();
|
|
|
|
void initVMA();
|
|
void destroyVMA();
|
|
|
|
void initCommandPools();
|
|
void destroyCommandPools();
|
|
|
|
void initPresentContext();
|
|
void destroyPresentContext();
|
|
|
|
void quertDepthFormatSupportState();
|
|
|
|
void initEngineAssets();
|
|
|
|
private:
|
|
EContextState m_state = EContextState::init;
|
|
|
|
// Instance of vulkan.
|
|
VkInstance m_instance = VK_NULL_HANDLE;
|
|
|
|
// Vulkan device.
|
|
VkDevice m_device = VK_NULL_HANDLE;
|
|
|
|
// Using gpu.
|
|
VkPhysicalDevice m_gpu = VK_NULL_HANDLE;
|
|
|
|
// AMD's vulkan memory allocator.
|
|
VmaAllocator m_vma = VK_NULL_HANDLE;
|
|
|
|
VkDebugUtilsMessengerEXT m_debugUtilsHandle = VK_NULL_HANDLE;
|
|
|
|
// Windows handle and surface handle, it can be nullptr when application run with console.
|
|
GLFWwindow* m_window = nullptr;
|
|
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
|
|
|
|
// Cache device infos.
|
|
VkPhysicalDeviceMemoryProperties m_memoryProperties;
|
|
VkPhysicalDeviceProperties m_deviceProperties;
|
|
VkPhysicalDeviceProperties2 m_deviceProperties2;
|
|
VkPhysicalDeviceSubgroupProperties m_subgroupProperties;
|
|
VkPhysicalDeviceDescriptorIndexingPropertiesEXT m_descriptorIndexingProperties;
|
|
VkPhysicalDeviceAccelerationStructurePropertiesKHR m_accelerationStructureProperties;
|
|
|
|
struct DeviceSupportStates
|
|
{
|
|
bool bSupportHDR = true;
|
|
|
|
bool bSupportRaytrace = true;
|
|
} m_graphicsSupportStates;
|
|
|
|
struct GPUQueuesInfo
|
|
{
|
|
uint32_t graphicsFamily = ~0;
|
|
uint32_t copyFamily = ~0;
|
|
uint32_t computeFamily = ~0;
|
|
|
|
std::vector<VkQueue> computeQueues; // Priority: #0 0.8f, #1...#n 0.5f
|
|
std::vector<VkQueue> copyQueues; // Priority: #0...#n 0.5f
|
|
std::vector<VkQueue> graphcisQueues; // Priority: #0 1.0f, #1 0.8f, #2...#n 0.5f
|
|
} m_queues;
|
|
|
|
// Shader cache.
|
|
ShaderCache m_shaderCache;
|
|
|
|
// Sampler cache.
|
|
SamplerCache m_samplerCache;
|
|
|
|
// Descriptor allocator.
|
|
DescriptorAllocator m_descriptorAllocator;
|
|
|
|
// Descriptor layout cache.
|
|
DescriptorLayoutCache m_descriptorLayoutCache;
|
|
|
|
// Windows swapchain.
|
|
Swapchain m_swapchain;
|
|
|
|
// Surface present used backbuffer format.
|
|
EBackBufferFormat m_backbufferFormat = EBackBufferFormat::SRGB_NonLinear;
|
|
|
|
// Sampler bindless.
|
|
BindlessSampler m_bindlessSampler;
|
|
|
|
// Texture bindless.
|
|
BindlessTexture m_bindlessTexture;
|
|
|
|
// Storage buffer bindless.
|
|
BindlessStorageBuffer m_bindlessStorageBuffer;
|
|
|
|
// Major graphics queue with priority 1.0f.
|
|
GPUCommandPool m_majorGraphicsPool;
|
|
|
|
// Major compute queue with priority 0.8f. Use for AsyncScheduler.
|
|
GPUCommandPool m_majorComputePool;
|
|
|
|
// Second major queue with priority 0.8f. Use fir Async Scheduler.
|
|
GPUCommandPool m_secondMajorGraphicsPool;
|
|
|
|
// Other command pool with priority 0.5f.
|
|
std::vector<GPUCommandPool> m_graphicsPools;
|
|
std::vector<GPUCommandPool> m_computePools;
|
|
|
|
// Copy pool used for async uploader.
|
|
std::vector<GPUCommandPool> m_copyPools;
|
|
|
|
struct PresentContext
|
|
{
|
|
bool bSwapchainChange = false;
|
|
uint32_t imageIndex;
|
|
uint32_t currentFrame = 0;
|
|
std::vector<VkSemaphore> semaphoresImageAvailable;
|
|
std::vector<VkSemaphore> semaphoresRenderFinished;
|
|
std::vector<VkFence> inFlightFences;
|
|
std::vector<VkFence> imagesInFlight;
|
|
} m_presentContext;
|
|
|
|
struct SwapchainRebuildContext
|
|
{
|
|
int currentWidth;
|
|
int currentHeight;
|
|
int lastWidth = ~0;
|
|
int lastHeight = ~0;
|
|
} m_swapchainRebuildContext;
|
|
|
|
// Cache support depth formats.
|
|
VkFormat m_cacheSupportDepthStencilFormat = VK_FORMAT_UNDEFINED;
|
|
VkFormat m_cacheSupportDepthOnlyFormat = VK_FORMAT_UNDEFINED;
|
|
|
|
std::unique_ptr<AsyncUploaderManager> m_uploader;
|
|
|
|
std::unique_ptr<LRUAssetCache> m_lru;
|
|
std::unordered_map<UUID, std::shared_ptr<LRUAssetInterface>> m_engineAssets;
|
|
std::unordered_map<UUID, StaticMeshRenderBounds> m_engineMeshBounds;
|
|
|
|
// Render texture pool.
|
|
std::unique_ptr<RenderTexturePool> m_rtPool;
|
|
|
|
std::unique_ptr<PassCollector> m_passCollector;
|
|
|
|
std::unique_ptr<DynamicUniformBuffer> m_dynamicUniformBuffer;
|
|
|
|
std::unique_ptr<BufferParameterPool> m_bufferParameters;
|
|
|
|
std::vector<std::vector<std::shared_ptr<GpuResource>>> m_gpuResourcePending;
|
|
};
|
|
|
|
extern VulkanContext* getContext();
|
|
} |