diff --git a/engine/modules/engine/render/include/render/asset/material.h b/engine/modules/engine/render/include/render/asset/material.h new file mode 100644 index 0000000..da87eb0 --- /dev/null +++ b/engine/modules/engine/render/include/render/asset/material.h @@ -0,0 +1,20 @@ +#pragma once +#include "asset/asset.h" +#include "shader.h" +namespace api { + class Material : public Asset { + protected: + RscHandle mShader; + + friend class Scene; + public: + Material(); + ~Material(); + void BeginLoad() { + mShader->BeginLoad(); + } + RscHandle GetShader() { + return mShader; + } + }; +}; \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/asset/mesh.h b/engine/modules/engine/render/include/render/asset/mesh.h new file mode 100644 index 0000000..3106a45 --- /dev/null +++ b/engine/modules/engine/render/include/render/asset/mesh.h @@ -0,0 +1,33 @@ +#pragma once +#include "material.h" +#include "vertex.h" +#include "refl/std/parray.h" +namespace api { + using refl::parray; + class Mesh : public Asset { + protected: + RscHandle mMaterial; + parray mVertices; + vector mIndices; + public: + Mesh(); + void BeginLoad(); + + public: + Guid GetShaderGuid() { + return mMaterial->GetShader().guid; + } + void SetMaterial(RscHandle material) { + mMaterial = material; + } + RscHandle GetMaterial() { + return mMaterial; + } + parray& GetVertices() { + return mVertices; + } + vector& GetIndices() { + return mIndices; + } + }; +}; \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/asset/shader.h b/engine/modules/engine/render/include/render/asset/shader.h new file mode 100644 index 0000000..87ee72f --- /dev/null +++ b/engine/modules/engine/render/include/render/asset/shader.h @@ -0,0 +1,25 @@ +#pragma once +#include "asset/res/resource_handle.h" +namespace api { + class ShaderProgram : public Resource {}; + class Shader : public Asset { + private: + UPROPERTY() + RscHandle mVert; + UPROPERTY() + RscHandle mFrag; + friend class Scene; + public: + Shader(); + ~Shader(); + void BeginLoad(); + template + RscHandle GetVertHandle() { + return mVert; + } + template + RscHandle GetFragHandle() { + return mFrag; + } + }; +}; \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/asset/vertex.h b/engine/modules/engine/render/include/render/asset/vertex.h new file mode 100644 index 0000000..33445ef --- /dev/null +++ b/engine/modules/engine/render/include/render/asset/vertex.h @@ -0,0 +1,46 @@ +#pragma once +#include "math/vector3.h" +#include "math/vector2.h" +#include "refl/pch.h" +// 顶点最多关联4个骨骼 +#define MAX_NUM_BONES_PER_VERTEX 4 +namespace api { + using refl::type_info; + struct Vertex {}; + struct PosVertex : public Vertex { + UPROPERTY_gl({}, glVertexMeta{ 3, GL_FLOAT, GL_FALSE }) + UPROPERTY_vk({}, uint32_t{ VK_FORMAT_R32G32B32_SFLOAT }) + Vector3 Position = {}; + }; + struct TexVertex : public Vertex { + UPROPERTY_gl({}, glVertexMeta{ 3, GL_FLOAT, GL_FALSE }) + UPROPERTY_vk({}, uint32_t{ VK_FORMAT_R32G32B32_SFLOAT }) + Vector3 Position = {}; + UPROPERTY_gl({}, glVertexMeta{ 2, GL_FLOAT, GL_FALSE }) + UPROPERTY_vk() + Vector2 TexCoords = {}; + UPROPERTY_gl({}, glVertexMeta{ 3, GL_FLOAT, GL_FALSE }) + UPROPERTY_vk() + Vector3 Normal = {}; + }; + struct BoneVertex : public Vertex + { + UPROPERTY_gl({}, glVertexMeta{ 3, GL_FLOAT, GL_FALSE }) + UPROPERTY_vk({}, uint32_t{ VK_FORMAT_R32G32B32_SFLOAT }) + Vector3 Position = {}; + UPROPERTY_gl({}, glVertexMeta{ 2, GL_FLOAT, GL_FALSE }) + UPROPERTY_vk() + Vector2 TexCoords = {}; + UPROPERTY_gl({}, glVertexMeta{ 3, GL_FLOAT, GL_FALSE }) + UPROPERTY_vk() + Vector3 Normal = {}; + UPROPERTY_gl({}, glVertexMeta{ 3, GL_FLOAT, GL_FALSE }) + UPROPERTY_vk() + Vector3 Tangent = {}; + // 骨骼蒙皮数据 + UPROPERTY_vk() + float Weights[MAX_NUM_BONES_PER_VERTEX] = {}; + UPROPERTY_vk() + uint32_t BoneIDs[MAX_NUM_BONES_PER_VERTEX] = {}; + }; +}; \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/renderapi.h b/engine/modules/engine/render/include/render/renderapi.h index 89c182e..f76dd1a 100644 --- a/engine/modules/engine/render/include/render/renderapi.h +++ b/engine/modules/engine/render/include/render/renderapi.h @@ -12,6 +12,11 @@ namespace api { public: RenderAPI() {}; virtual ~RenderAPI() {}; + public: + void* operator new(size_t size) { + return ::operator new(size, GlobalPool()); + } + void operator delete(void* p) {} public: virtual void Init() = 0; virtual void Shutdown() = 0; diff --git a/engine/modules/engine/render/include/render/window.h b/engine/modules/engine/render/include/render/window.h index 9d51351..a9a5a12 100644 --- a/engine/modules/engine/render/include/render/window.h +++ b/engine/modules/engine/render/include/render/window.h @@ -1,6 +1,7 @@ #pragma once #include #include "singleton.h" +#include "pmr/frame_allocator.h" namespace api { class RENDER_API Window : public Singleton { protected: @@ -13,6 +14,11 @@ namespace api { bool resizeable = true; bool headless = false; }; + public: + void* operator new(size_t size) { + return ::operator new(size, GlobalPool()); + } + void operator delete(void* p) {} public: Window(CreatePFN func, const Args& args, int width, int height) noexcept; SDL_Window* GetPtr() { return mPtr; } diff --git a/engine/modules/render/vulkan/include/vkn/thread/worker.cpp b/engine/modules/engine/render/src/asset/material.cpp similarity index 100% rename from engine/modules/render/vulkan/include/vkn/thread/worker.cpp rename to engine/modules/engine/render/src/asset/material.cpp diff --git a/engine/modules/engine/render/src/asset/mesh.cpp b/engine/modules/engine/render/src/asset/mesh.cpp new file mode 100644 index 0000000..cc5d5eb --- /dev/null +++ b/engine/modules/engine/render/src/asset/mesh.cpp @@ -0,0 +1,7 @@ +#include "render/asset/mesh.h" +namespace api { + Mesh::Mesh() : Asset(type_info()) + { + + } +} \ No newline at end of file diff --git a/engine/modules/engine/render/src/asset/shader.cpp b/engine/modules/engine/render/src/asset/shader.cpp new file mode 100644 index 0000000..e69de29 diff --git a/engine/modules/engine/zlib/include/refl/macro.h b/engine/modules/engine/zlib/include/refl/macro.h index ac7a07b..86443fb 100644 --- a/engine/modules/engine/zlib/include/refl/macro.h +++ b/engine/modules/engine/zlib/include/refl/macro.h @@ -6,6 +6,10 @@ #define UPROPERTY(...) __Meta(__VA_ARGS__) #define UFUNCTION(...) __Meta(__VA_ARGS__) +#define __glMeta(...) __cppast(glMeta=__VA_ARGS__) +#define UPROPERTY_gl(...) __glMeta(__VA_ARGS__) +#define UFUNCTION_gl(...) __glMeta(__VA_ARGS__) + #define __vkMeta(...) __cppast(vkMeta=__VA_ARGS__) #define UPROPERTY_vk(...) __vkMeta(__VA_ARGS__) #define UFUNCTION_vk(...) __vkMeta(__VA_ARGS__) diff --git a/engine/modules/engine/zlib/include/refl/std/parray.h b/engine/modules/engine/zlib/include/refl/std/parray.h new file mode 100644 index 0000000..33802f1 --- /dev/null +++ b/engine/modules/engine/zlib/include/refl/std/parray.h @@ -0,0 +1,73 @@ +#include "refl/refl.h" +namespace refl { + template + class parray { + protected: + const UClass* m_cls; + T* m_ptr; + int m_count; + public: + parray(): m_cls(nullptr), m_ptr(nullptr),m_count(0) {} + template + requires std::is_base_of_v + parray(std::vector& vec) : m_cls(&TypeInfo::StaticClass), m_ptr(nullptr){ + m_count = vec.size(); + if (m_count > 0) { + C* ptr = new C[m_count]; + m_ptr = ptr; + if constexpr (std::is_trivially_copyable_v) { + memcpy(m_ptr, vec.data(), m_count * sizeof(C)); + } + else { + for (int i = 0; i < m_count; i++) { + new(ptr + i) Vertex(vec[i]); + } + } + } + } + parray(parray& parr) : m_cls(parr.m_cls) + , m_ptr(parr.data()), m_count(parr.size()) { + parr.reset(); + } + ~parray() { + if (!m_count || !m_cls) + return; + auto dest = m_cls->vtable.Destruct; + if (dest) { + for (int i = 0; i < m_count; i++) { + dest((char*)m_ptr + (i * m_cls->size)); + } + } + m_count = 0; + m_ptr = nullptr; + } + T* at(int i)noexcept { + if(i < m_count) + return (T*)((char*)m_ptr + (i * m_cls->size)); + return nullptr; + } + T* data() noexcept{ + return m_ptr; + } + void reset() noexcept { + m_ptr = nullptr; + m_count = 0; + } + int size() const noexcept { + return m_count; + } + int data_size()const noexcept { + return m_count * m_cls->size; + } + int capicty() const noexcept { + return m_count * m_cls->size; + } + const UClass* uclass()const noexcept { + return m_cls; + } + }; + template + parray ToParray(std::vector& vec){ + return parray{vec}; + } +} diff --git a/engine/modules/engine/zlib/include/std/channel.h b/engine/modules/engine/zlib/include/std/channel.h new file mode 100644 index 0000000..525a814 --- /dev/null +++ b/engine/modules/engine/zlib/include/std/channel.h @@ -0,0 +1,58 @@ +#pragma once +#include +#include +#include +namespace zstd { + template + class channel { + protected: + int m_tail; + int m_head; + int m_size; + T* m_buf; + std::mutex m_mtx; + std::condition_variable m_cv; + public: + ~channel() { + reset(); + free(m_buf); + } + channel(int size = 1) : m_tail(0), m_head(0), m_buf((T*)malloc(sizeof(T)* size)), m_size(size) {} + int head() { + return m_head; + } + int tail() { + return m_tail; + } + int count() { + return m_head - m_tail; + } + void reset() { + for (int i = m_tail; i < m_head; i++) { + std::destroy_at(m_buf + (m_tail % m_size)); + } + m_tail = 0; + m_head = 0; + } + template + void release(Args... args) { + std::unique_lock lck(m_mtx); + while (m_head >= m_tail + m_size) { + m_cv.wait(lck); + } + std::construct_at(m_buf + m_head % m_size, std::forward(args)...); + if(m_head++ == m_tail) + m_cv.notify_one(); + }; + T acquire() {//不能传右值引用,右值引用拷贝地址数据不在锁保护范围内 + std::unique_lock lck(m_mtx); + while (m_tail >= m_head) { + m_cv.wait(lck); + } + int tail = m_tail % m_size; + if(m_tail++ == m_head - m_size) + m_cv.notify_one(); + return std::move(*(m_buf + tail)); + }; + }; +} \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/backend.h b/engine/modules/render/vulkan/include/vkn/backend.h index 6e6ac7b..d387afe 100644 --- a/engine/modules/render/vulkan/include/vkn/backend.h +++ b/engine/modules/render/vulkan/include/vkn/backend.h @@ -1,6 +1,22 @@ #pragma once +#include "thread/worker.h" namespace vkn { + class Device; + class Instance; class Backend { + protected: + Instance* mInstance; + Device* mDevice; + table mWorkerMap; + public: + Backend(string_view appName); + ~Backend(); + void InitWorker(Name name, VkCommandPoolCreateFlags flag); + CommandWorker* GetWorker(Name name); + public: + static CommandWorker* TransferWorker; + static CommandWorker* RenderWorker; + static CommandWorker* PresentWorker; }; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/thread/thread_worker.h b/engine/modules/render/vulkan/include/vkn/thread/thread_worker.h new file mode 100644 index 0000000..efbee25 --- /dev/null +++ b/engine/modules/render/vulkan/include/vkn/thread/thread_worker.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include "vkn/type.h" +#include +namespace vkn { + class CommandThreadWorker { + protected: + std::thread mThread; + Name mName; + channel mChannel; + std::binary_semaphore mSemaphore; + protected: + void workloop(); + public: + CommandThreadWorker(Name name, int buffer); + ~CommandThreadWorker(); + + void Invoke(const voidFn& fn); + void SyncInvoke(const voidFn& fn); + }; +}; diff --git a/engine/modules/render/vulkan/include/vkn/thread/worker.h b/engine/modules/render/vulkan/include/vkn/thread/worker.h index e69de29..b643f32 100644 --- a/engine/modules/render/vulkan/include/vkn/thread/worker.h +++ b/engine/modules/render/vulkan/include/vkn/thread/worker.h @@ -0,0 +1,32 @@ +#pragma once +#include "vkn/wrapper/commandpool.h" +#include "thread_worker.h" +namespace vkn { + class Device; + class Queue; + class CommandWorker { + protected: + Device& mDevice; + Queue& mQueue; + Name mName; + CommandThreadWorker mWork; + CommandPool mCommandPool; + CommandBuffer mImmediateExeCmd; + public: + CommandWorker(Name name, Device& device, Queue& queue, VkCommandPoolCreateFlags queueFlags); + CommandPool& GetCommandPool() { + return mCommandPool; + } + Queue& GetQueue() { + return mQueue; + } + void Invoke(const voidFn& fn); + void InvokeBuffer(const commandFn& fn, const voidFn& callback); + void Buffer(CommandBuffer& cmd, const commandFn& fn, const voidFn& callback); + void Flush(); + void ImmediatelyExecute(const commandFn& fn, const voidFn callback) { + Buffer(mImmediateExeCmd, fn , callback); + } + bool Present(VkPresentInfoKHR& presentInfo); + }; +}; \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/type.h b/engine/modules/render/vulkan/include/vkn/type.h index e94a4c4..f8b43cb 100644 --- a/engine/modules/render/vulkan/include/vkn/type.h +++ b/engine/modules/render/vulkan/include/vkn/type.h @@ -1,10 +1,19 @@ #pragma once +#include "std/channel.h" +#include "pmr/frame_allocator.h" +#include "pmr/name.h" #include #include #define VK_NO_PROTOTYPES #include "volk/volk.h" -#include -#include +#define Z_RENDER_DEBUG 1 namespace vkn { - + using pmr::Name; + using pmr::table; + using std::string_view; + using zstd::channel; + inline constexpr string_view VulkanEngineName = "vulkan"; + class CommandBuffer; + using voidFn = std::function; + using commandFn = std::function; } \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_api.h b/engine/modules/render/vulkan/include/vkn/vulkan_api.h index bacd294..2e1dcf1 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_api.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_api.h @@ -1,11 +1,14 @@ #pragma once #include "type.h" #include "render/renderapi.h" +#include "backend.h" namespace vkn { + class Backend; class VulkanWindow; - class VulkanAPI : public api::RenderAPI { + class VULKAN_API VulkanAPI : public api::RenderAPI { private: - VulkanWindow* window; + VulkanWindow& window; + Backend backend; public: VulkanAPI(); diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_window.h b/engine/modules/render/vulkan/include/vkn/vulkan_window.h index b5614ff..e375955 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_window.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_window.h @@ -5,8 +5,17 @@ namespace vkn { class VulkanWindow : public api::Window { private: VkSurfaceKHR mSurfaceKHR; + public: + void* operator new(size_t size) { + return ::operator new(size, GlobalPool()); + } + void operator delete(void* p) {} public: using api::Window::Window; void CreateRender(); + static VulkanWindow* Ptr() { + //return dynamic_cast(api::Window::Ptr()); + return (VulkanWindow*)api::Window::Ptr(); + } }; } \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/wrapper/commandbuffer.h b/engine/modules/render/vulkan/include/vkn/wrapper/commandbuffer.h new file mode 100644 index 0000000..b72724c --- /dev/null +++ b/engine/modules/render/vulkan/include/vkn/wrapper/commandbuffer.h @@ -0,0 +1,21 @@ +#pragma once +#include "vkn/type.h" +namespace vkn { + class CommandBuffer { + protected: + VkCommandBuffer mPtr; + public: + CommandBuffer(VkCommandBuffer ptr) : mPtr(ptr) {}; + VkCommandBuffer& Ptr() { + return mPtr; + }; + void Reset(); + void BeginRecord(VkCommandBufferUsageFlags flag); + void EndRecord(); + void CmdCopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); + void Submit(VkQueue& queue,VkFence fence); + + void BindVertexBuffer(VkBuffer buffer, uint32_t offset); + void BindIndexBuffers(VkBuffer buffer, uint32_t offset, VkIndexType type); + }; +} \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/wrapper/commandpool.h b/engine/modules/render/vulkan/include/vkn/wrapper/commandpool.h new file mode 100644 index 0000000..940a406 --- /dev/null +++ b/engine/modules/render/vulkan/include/vkn/wrapper/commandpool.h @@ -0,0 +1,22 @@ +#pragma once +#include "commandbuffer.h" +namespace vkn { + class Device; + class Queue; + class CommandPool { + protected: + VkCommandPool mPtr; + Device& mDevice; + pmr::vector mPool; + public: + CommandPool(Device& device, VkCommandPoolCreateFlags queueFlags, uint32_t queueIndex); + ~CommandPool(); + VkCommandBuffer AllocateBuffer(VkCommandBufferLevel level); + void FreeBuffer(VkCommandBuffer& buf); + VkCommandPool& Ptr() { + return mPtr; + }; + CommandBuffer Pop(); + void Push(CommandBuffer& cmd); + }; +} \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/wrapper/device.h b/engine/modules/render/vulkan/include/vkn/wrapper/device.h index e69de29..949705f 100644 --- a/engine/modules/render/vulkan/include/vkn/wrapper/device.h +++ b/engine/modules/render/vulkan/include/vkn/wrapper/device.h @@ -0,0 +1,33 @@ +#pragma once +#include "vkn/type.h" +namespace vkn { + class DeviceCreator; + class Queue; + class Device { + friend class DeviceCreator; + protected: + VkDevice mPtr{ NULL }; + VkPhysicalDevice mPhysical{ NULL }; + table mQueueMap; + pmr::vector mFencePool; + std::mutex mFenceMutex; + public: + VkDevice& Ptr() { + return mPtr; + } + VkPhysicalDevice GetPhysical() { + return mPhysical; + } + public: + Device(DeviceCreator& Creator); + ~Device(); + + VkFence CreateFence(VkFenceCreateFlags flags); + Queue* GetQueue(Name name); + VkFence PopFence(); + void PushWaitFence(VkFence fence); + VkSemaphore CreateSemaphore(); + VkShaderModule CreateShaderModule(pmr::vector code); + VkShaderModule CreateShaderModule(pmr::vector code); + }; +}; \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/wrapper/device_create.h b/engine/modules/render/vulkan/include/vkn/wrapper/device_create.h index e69de29..93bb395 100644 --- a/engine/modules/render/vulkan/include/vkn/wrapper/device_create.h +++ b/engine/modules/render/vulkan/include/vkn/wrapper/device_create.h @@ -0,0 +1,50 @@ +#pragma once +#include "vkn/type.h" +namespace vkn { + class Instance; + class DeviceCreator { + private: + class DesiredQueue final + { + public: + Name name; + VkQueueFlags flag; + float prioritie; + int queueFamilyIndex; + DesiredQueue(Name name, VkQueueFlags flag, float prioritie) + : name(name), flag(flag), prioritie(prioritie), queueFamilyIndex(0) {} + }; + public: + VkPhysicalDeviceFeatures desiredPhysicalDeviceFeatures; + VkPhysicalDeviceType desiredPhysicalDeviceType; + pmr::vector desiredExtensions; + pmr::vector desiredQueues; + int fencePoolCount = 256; + Instance& instance; + public: + DeviceCreator(Instance& instance); + + void AddQueue(Name name, VkQueueFlags flag, float prioritie); + void AddExtension(string_view extensionName); + void AddWindowExtension(); + bool CheckProperty(const VkPhysicalDevice device); + bool CheckExtension(const VkPhysicalDevice device); + bool FindDevice(VkPhysicalDevice& device); + void QueueCreateInfos(pmr::vector& queue_create_infos, + pmr::vector>& queue_prioritie, + pmr::vector& queue_families); + pmr::vector EnabledExtensionNames(); + void EnableDeviceFeatures(); + VkPhysicalDeviceFeatures2 GetDeviceFeature2(); + VkPhysicalDeviceVulkan12Features GetVulkan12Features(); +#ifdef Z_RENDER_DEBUG + public: + pmr::vector desiredLayers; + void AddLayer(string_view layerName); + bool CheckLayer(const VkPhysicalDevice device); + pmr::vector EnabledLayerNames(); +#endif + public: + static bool CheckAvailableQueueFamilies(VkPhysicalDevice physical_device, pmr::vector& queue_families); + }; +}; \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/wrapper/instance.h b/engine/modules/render/vulkan/include/vkn/wrapper/instance.h index e69de29..ef69543 100644 --- a/engine/modules/render/vulkan/include/vkn/wrapper/instance.h +++ b/engine/modules/render/vulkan/include/vkn/wrapper/instance.h @@ -0,0 +1,23 @@ +#pragma once +#include "vkn/type.h" + +namespace vkn { + class InstanceCreator; + class Instance { + friend class InstanceCreator; + protected: + VkInstance mPtr; + public: + Instance(InstanceCreator& Creator); + + VkInstance& Ptr() { + return mPtr; + } + bool EnumerateAvailablePhysicalDevices(pmr::vector& available_devices); + + static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT, + VkDebugUtilsMessageTypeFlagsEXT, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void*); + }; +}; \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/wrapper/instance_create.h b/engine/modules/render/vulkan/include/vkn/wrapper/instance_create.h index e69de29..b78b4de 100644 --- a/engine/modules/render/vulkan/include/vkn/wrapper/instance_create.h +++ b/engine/modules/render/vulkan/include/vkn/wrapper/instance_create.h @@ -0,0 +1,42 @@ +#pragma once +#include "vkn/type.h" +namespace vkn { + class InstanceCreator { + public: + pmr::string appName; + uint32_t appVersion; + pmr::string engineName; + uint32_t engineVersion; + uint32_t apiVersion; + + pmr::vector desiredExtensions; + pmr::vector desiredLayers; + +#ifdef Z_RENDER_DEBUG + VkDebugUtilsMessageSeverityFlagsEXT messageSeverity; + VkDebugUtilsMessageTypeFlagsEXT messageType; + PFN_vkDebugUtilsMessengerCallbackEXT debugCallback; + + VkDebugUtilsMessengerCreateInfoEXT DebugUtilsLayerNext(); +#endif + public: + InstanceCreator(); + void AddExtension(string_view extensionName); + void AddLayer(string_view layerName); + + void AddWindowExtension(); + void AddInstanceExtension(); + void AddDebugExtension(); + + pmr::vector EnabledExtensionNames(); + pmr::vector EnabledLayerNames(); + + private: + static bool CheckAvailableInstanceExtensions(pmr::vector& available_extensions); + static bool CheckAvailableInstanceLayers(pmr::vector& available_layers); + static bool IsExtensionSupported(pmr::vector const& available_extensions, + char const* const extension); + static bool IsLayerSupported(pmr::vector const& available_layers, + char const* const layer); + }; +}; \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/wrapper/queue.h b/engine/modules/render/vulkan/include/vkn/wrapper/queue.h new file mode 100644 index 0000000..7c30fdd --- /dev/null +++ b/engine/modules/render/vulkan/include/vkn/wrapper/queue.h @@ -0,0 +1,26 @@ +#pragma once +#include "vkn/type.h" +namespace vkn { + class Device; + class CommandBuffer; + class Queue { + protected: + VkQueue mPtr; + uint32_t mQueueFamilyIndex; + const Name mName; + public: + Queue(Name name, uint32_t queueFamilyIndex, VkQueue queue); + uint32_t QueueFamilyIndex() + { + return mQueueFamilyIndex; + } + VkQueue& Ptr() { + return mPtr; + } + public: + static const Name TransferQueue; + static const Name RenderQueue; + static const Name ComputeQueue; + static const Name PresentQueue; + }; +} \ No newline at end of file diff --git a/engine/modules/render/vulkan/src/backend.cpp b/engine/modules/render/vulkan/src/backend.cpp index e69de29..106a7f6 100644 --- a/engine/modules/render/vulkan/src/backend.cpp +++ b/engine/modules/render/vulkan/src/backend.cpp @@ -0,0 +1,50 @@ +#include "vkn/backend.h" +#include "vkn/wrapper/device.h" +#include "vkn/wrapper/device_create.h" +#include "vkn/wrapper/instance.h" +#include "vkn/wrapper/instance_create.h" +#include "vkn/wrapper/queue.h" +namespace vkn { + Backend::Backend(string_view appName) : mWorkerMap(GlobalPool()) + { + InstanceCreator instanceCreator{}; + mInstance = new (GlobalPool()) Instance(instanceCreator); + + DeviceCreator deviceCreator = DeviceCreator{ *mInstance }; + deviceCreator.AddWindowExtension(); + deviceCreator.AddQueue(Queue::TransferQueue,VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT, 1.0); + deviceCreator.AddQueue(Queue::RenderQueue, VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT, 1.0); + deviceCreator.AddQueue(Queue::ComputeQueue, VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT, 1.0); + deviceCreator.AddQueue(Queue::PresentQueue, VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT, 1.0); + mDevice = new (GlobalPool()) Device(deviceCreator); + + InitWorker(Queue::TransferQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + InitWorker(Queue::RenderQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + InitWorker(Queue::ComputeQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + InitWorker(Queue::PresentQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + + Backend::TransferWorker = GetWorker(Queue::TransferQueue); + Backend::RenderWorker = GetWorker(Queue::RenderQueue); + } + Backend::~Backend() + { + mInstance->~Instance(); + mDevice->~Device(); + } + void Backend::InitWorker(Name name, VkCommandPoolCreateFlags flag) + { + auto queue = mDevice->GetQueue(name); + if (queue) { + auto worker = new CommandWorker(name, *mDevice, *queue, flag); + mWorkerMap.emplace(name, worker); + } + } + CommandWorker* Backend::GetWorker(Name name) + { + auto it = mWorkerMap.find(name); + if (it != mWorkerMap.end()) { + return it->second; + } + return nullptr; + } +} diff --git a/engine/modules/render/vulkan/src/thread/thread_worker.cpp b/engine/modules/render/vulkan/src/thread/thread_worker.cpp new file mode 100644 index 0000000..37fb85d --- /dev/null +++ b/engine/modules/render/vulkan/src/thread/thread_worker.cpp @@ -0,0 +1,36 @@ +#include "vkn/thread/thread_worker.h" +#include "zlog.h" +namespace vkn { + CommandThreadWorker::CommandThreadWorker(Name name, int buffer) + : mName(name) + , mChannel(buffer) + , mSemaphore(0) + { + mThread = std::thread(&CommandThreadWorker::workloop, this); + } + CommandThreadWorker::~CommandThreadWorker() { + zlog::info("~CommandThreadWorker"); + zlog::flush(); + } + void CommandThreadWorker::workloop() + { + mThread.detach(); + while (true) { + voidFn fn = mChannel.acquire(); + fn(); + } + } + void CommandThreadWorker::Invoke(const voidFn& fn) + { + mChannel.release(fn); + } + + void CommandThreadWorker::SyncInvoke(const voidFn& fn) + { + Invoke([=,this]() { + fn(); + mSemaphore.release(); + }); + mSemaphore.acquire(); + } +} diff --git a/engine/modules/render/vulkan/src/thread/worker.cpp b/engine/modules/render/vulkan/src/thread/worker.cpp new file mode 100644 index 0000000..6d08edc --- /dev/null +++ b/engine/modules/render/vulkan/src/thread/worker.cpp @@ -0,0 +1,47 @@ +#include "vkn/thread/worker.h" +#include "vkn/wrapper/queue.h" +#include "vkn/wrapper/device.h" +namespace vkn { + CommandWorker::CommandWorker(Name name, Device& device, Queue& queue, VkCommandPoolCreateFlags queueFlags) + :mName(name) + ,mDevice(device) + ,mQueue(queue) + ,mCommandPool(device, queueFlags, queue.QueueFamilyIndex()) + ,mWork(name, 64) + ,mImmediateExeCmd(mCommandPool.AllocateBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY)) + { + } + void CommandWorker::Invoke(const voidFn& fn) + { + mWork.Invoke(fn); + } + + void CommandWorker::InvokeBuffer(const commandFn& fn, const voidFn& callback) + { + mWork.Invoke([=, this]() { + CommandBuffer cmd = mCommandPool.Pop(); + Buffer(cmd, fn, callback); + mCommandPool.Push(cmd); + }); + } + void CommandWorker::Buffer(CommandBuffer& cmd, const commandFn& fn, const voidFn& callback) + { + cmd.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + fn(cmd); + cmd.EndRecord(); + VkFence fence = mDevice.PopFence(); + cmd.Submit(mQueue.Ptr(), fence); + mDevice.PushWaitFence(fence); + callback(); + } + + void CommandWorker::Flush() + { + mWork.SyncInvoke([]{}); + } + bool CommandWorker::Present(VkPresentInfoKHR& presentInfo) + { + VkResult result = vkQueuePresentKHR(mQueue.Ptr(), &presentInfo); + return result == VK_SUCCESS; + } +} diff --git a/engine/modules/render/vulkan/src/vulkan_api.cpp b/engine/modules/render/vulkan/src/vulkan_api.cpp index 5cba57e..e6e95fb 100644 --- a/engine/modules/render/vulkan/src/vulkan_api.cpp +++ b/engine/modules/render/vulkan/src/vulkan_api.cpp @@ -1,10 +1,9 @@ #include "vkn/vulkan_api.h" #include "vkn/vulkan_window.h" namespace vkn { - VulkanAPI::VulkanAPI() + VulkanAPI::VulkanAPI() : window(*VulkanWindow::Ptr()), backend(VulkanEngineName) { - window = (VulkanWindow*) api::Window::Ptr(); - window->CreateRender(); + } void VulkanAPI::Init() { diff --git a/engine/modules/render/vulkan/src/wrapper/commandbuffer.cpp b/engine/modules/render/vulkan/src/wrapper/commandbuffer.cpp new file mode 100644 index 0000000..454b68b --- /dev/null +++ b/engine/modules/render/vulkan/src/wrapper/commandbuffer.cpp @@ -0,0 +1,46 @@ +#include "vkn/wrapper/commandbuffer.h" +namespace vkn { + void CommandBuffer::Reset() + { + vkResetCommandBuffer(mPtr, VkCommandBufferResetFlagBits::VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + } + void CommandBuffer::BeginRecord(VkCommandBufferUsageFlags flag) + { + VkCommandBufferBeginInfo beginInfo{ + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,//sType + nullptr, //pNext + flag //flags + }; + vkBeginCommandBuffer(mPtr, &beginInfo); + } + void CommandBuffer::EndRecord() + { + vkEndCommandBuffer(mPtr); + } + void CommandBuffer::CmdCopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) + { + VkBufferCopy copy = {}; + copy.dstOffset = 0; + copy.srcOffset = 0; + copy.size = size; + vkCmdCopyBuffer(mPtr, srcBuffer, dstBuffer, 1, ©); + } + void CommandBuffer::Submit(VkQueue& queue, VkFence fence) + { + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &mPtr; + vkQueueSubmit(queue, 1, &submitInfo, fence); + } + void CommandBuffer::BindVertexBuffer(VkBuffer buffer, uint32_t offset) + { + VkDeviceSize offsets[] = { offset }; + vkCmdBindVertexBuffers(mPtr, 0, 1, &buffer, offsets); + } + void CommandBuffer::BindIndexBuffers(VkBuffer buffer, uint32_t offset, VkIndexType type) + { + vkCmdBindIndexBuffer(mPtr, buffer, offset, type); + } +} + diff --git a/engine/modules/render/vulkan/src/wrapper/commandpool.cpp b/engine/modules/render/vulkan/src/wrapper/commandpool.cpp new file mode 100644 index 0000000..eab72eb --- /dev/null +++ b/engine/modules/render/vulkan/src/wrapper/commandpool.cpp @@ -0,0 +1,58 @@ +#include "vkn/wrapper/commandpool.h" +#include "vkn/wrapper/device.h" +#include "vkn/wrapper/queue.h" +#include "zlog.h" +namespace vkn { + CommandPool::CommandPool(Device& device, VkCommandPoolCreateFlags queueFlags, uint32_t queueIndex) + :mPtr(nullptr) + ,mDevice(device) + { + VkCommandPoolCreateInfo pCreateInfo{ + VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + nullptr, + queueFlags, + queueIndex + }; + vkCreateCommandPool(device.Ptr(), &pCreateInfo, nullptr, &mPtr); + } + CommandPool::~CommandPool() + { + for (auto cb : mPool) { + FreeBuffer(cb.Ptr()); + } + mPool.clear(); + } + VkCommandBuffer CommandPool::AllocateBuffer(VkCommandBufferLevel level) + { + VkCommandBufferAllocateInfo allocInfo{ + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, //sType + nullptr, //pNext + mPtr, //commandPool + level, //level + 1, //commandBufferCount + }; + VkCommandBuffer cmd; + vkAllocateCommandBuffers(mDevice.Ptr(), &allocInfo, &cmd); + return cmd; + } + void CommandPool::FreeBuffer(VkCommandBuffer& buf) + { + vkFreeCommandBuffers(mDevice.Ptr(), mPtr, 1, &buf); + buf = nullptr; + } + CommandBuffer CommandPool::Pop() + { + if (mPool.empty()) { + return AllocateBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY); + } + CommandBuffer buffer = mPool.back(); + mPool.pop_back(); + return buffer; + } + void CommandPool::Push(CommandBuffer& cmd) + { + cmd.Reset(); + mPool.push_back(cmd); + } +} + diff --git a/engine/modules/render/vulkan/src/wrapper/device.cpp b/engine/modules/render/vulkan/src/wrapper/device.cpp index e69de29..7c7430b 100644 --- a/engine/modules/render/vulkan/src/wrapper/device.cpp +++ b/engine/modules/render/vulkan/src/wrapper/device.cpp @@ -0,0 +1,124 @@ +#include "vkn/wrapper/device.h" +#include "vkn/wrapper/device_create.h" +#include "vkn/wrapper/queue.h" +#include "zlog.h" +namespace vkn { + Device::Device(DeviceCreator& Creator) : mQueueMap(GlobalPool()) + { + //物理设备 + Creator.FindDevice(mPhysical); + //队列信息 + pmr::vector queue_families{FramePool()}; + Creator.CheckAvailableQueueFamilies(mPhysical, queue_families); + pmr::vector queue_create_infos{ FramePool() }; + pmr::vector> queue_prioritie; + Creator.QueueCreateInfos(queue_create_infos, queue_prioritie, queue_families); + //扩展 + auto extensions = Creator.EnabledExtensionNames(); + //特性 + VkPhysicalDeviceFeatures2 deviceFeatures = Creator.GetDeviceFeature2(); + VkPhysicalDeviceVulkan12Features deviceVulkan12Features = Creator.GetVulkan12Features(); + deviceFeatures.pNext = &deviceVulkan12Features; + VkDeviceCreateInfo device_create_info = { + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType + &deviceFeatures, // const void * pNext + 0, // VkDeviceCreateFlags flags + static_cast(queue_create_infos.size()), // uint32_t queueCreateInfoCount + queue_create_infos.data(), // const VkDeviceQueueCreateInfo * pQueueCreateInfos + 0, // uint32_t enabledLayerCount + nullptr, // const char * const * ppEnabledLayerNames + static_cast(extensions.size()), // uint32_t enabledExtensionCount + extensions.data(), // const char * const * ppEnabledExtensionNames + nullptr // const VkPhysicalDeviceFeatures * pEnabledFeatures + }; +#ifdef Z_USE_GRAPHIC_DEBUG + auto layers = Creator.EnabledLayerNames(); + device_create_info.enabledLayerCount = layers.size(); + device_create_info.ppEnabledLayerNames = layers.data(); +#endif // Z_USE_GRAPHIC_DEBUG + VkResult result = vkCreateDevice(mPhysical, &device_create_info, nullptr, &mPtr); + if ((result != VK_SUCCESS) || (mPtr == VK_NULL_HANDLE)) { + zlog::error("Could not create logical device. VkResult {}", (int)result); + } + volkLoadDevice(mPtr); + for (auto& queue : Creator.desiredQueues) { + Queue* gq = new (GlobalPool()) Queue(queue.name, queue.queueFamilyIndex, VK_NULL_HANDLE); + vkGetDeviceQueue(mPtr, queue.queueFamilyIndex, 0, &(gq->Ptr())); + mQueueMap.emplace(queue.name, gq); + } + } + Device::~Device() + { + for (auto& queue : mQueueMap) { + queue.second->~Queue(); + } + mQueueMap.clear(); + } + VkFence Device::CreateFence(VkFenceCreateFlags flags) + { + VkFenceCreateInfo fenceInfo{}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + // 创建时立刻设置为signaled状态(否则第一次永远等不到) + fenceInfo.flags = flags; + VkFence fence; + VkResult result = vkCreateFence(mPtr, &fenceInfo, nullptr, &fence); + return fence; + } + Queue* Device::GetQueue(Name name) + { + auto it = mQueueMap.find(name); + if (it != mQueueMap.end()) { + return it->second; + } + return nullptr; + } + VkFence Device::PopFence() + { + if (mFencePool.empty()) { + return CreateFence(0); + } + std::lock_guard lock(mFenceMutex); + VkFence fence = mFencePool.back(); + mFencePool.pop_back(); + return fence; + } + void Device::PushWaitFence(VkFence fence) + { + vkWaitForFences(mPtr, 1, &fence, VK_TRUE, UINT64_MAX); + vkResetFences(mPtr, 1, &fence); + std::lock_guard lock(mFenceMutex); + mFencePool.push_back(fence); + } + VkSemaphore Device::CreateSemaphore() + { + VkSemaphoreCreateInfo semaphoreInfo = {}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + VkSemaphore semaphore; + VkResult result = vkCreateSemaphore(mPtr, &semaphoreInfo, nullptr, &semaphore); + return semaphore; + } + VkShaderModule Device::CreateShaderModule(pmr::vector code) + { + VkShaderModuleCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + // 这里需要确保数据满足uint32_t的对齐要求,存储在vector中,默认分配器已经确保数据满足最差情况下的对齐要求 + createInfo.codeSize = code.size(); + // 转换为Vulkan要求的uint32_t指针 + createInfo.pCode = reinterpret_cast(code.data()); + VkShaderModule module; + VkResult result = vkCreateShaderModule(mPtr, &createInfo, nullptr, &module); + return module; + } + VkShaderModule Device::CreateShaderModule(pmr::vector code) + { + VkShaderModuleCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + //code size 是字节大小,需要 * sizeof + createInfo.codeSize = code.size() * sizeof(uint32_t); + // 转换为Vulkan要求的uint32_t指针 + createInfo.pCode = reinterpret_cast(code.data()); + VkShaderModule module; + VkResult result = vkCreateShaderModule(mPtr, &createInfo, nullptr, &module); + return module; + } +} diff --git a/engine/modules/render/vulkan/src/wrapper/device_create.cpp b/engine/modules/render/vulkan/src/wrapper/device_create.cpp new file mode 100644 index 0000000..2046044 --- /dev/null +++ b/engine/modules/render/vulkan/src/wrapper/device_create.cpp @@ -0,0 +1,211 @@ +#include "vkn/wrapper/device_create.h" +#include "vkn/wrapper/instance.h" +#include "zlog.h" +namespace vkn { + DeviceCreator::DeviceCreator(Instance& instance) + : instance(instance) + , desiredPhysicalDeviceType(VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + , desiredPhysicalDeviceFeatures() + , desiredExtensions{FramePool()} + , desiredQueues{ FramePool() } +#ifdef Z_RENDER_DEBUG + , desiredLayers{FramePool()} +#endif + { + } + void DeviceCreator::AddQueue(Name name, VkQueueFlags flag, float prioritie) + { + desiredQueues.emplace_back(name, flag, prioritie); + } + void DeviceCreator::AddExtension(string_view extensionName) + { + desiredExtensions.push_back(pmr::string{ extensionName , FramePool()}); + } + void DeviceCreator::AddWindowExtension() + { + AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); +#ifdef Z_RENDER_DEBUG + AddLayer("VK_LAYER_KHRONOS_validation"); + AddLayer("VK_LAYER_RENDERDOC_Capture"); +#endif + } + bool DeviceCreator::CheckProperty(const VkPhysicalDevice device) + { + VkPhysicalDeviceProperties deviceProperties; + vkGetPhysicalDeviceProperties(device, &deviceProperties); + return (deviceProperties.deviceType & desiredPhysicalDeviceType) == desiredPhysicalDeviceType; + } + bool DeviceCreator::CheckExtension(const VkPhysicalDevice device) + { + uint32_t extensionCount = 0; + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); + pmr::vector availableExtensions{FramePool()}; + availableExtensions.resize(extensionCount); + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data()); + for (const auto& desiredExtension : desiredExtensions) + { + bool find = false; + for (const auto& availableExtension : availableExtensions) + { + if (strcmp(availableExtension.extensionName, desiredExtension.c_str()) == 0) + { + find = true; + break; + } + } + if (!find)return false; + } + return true; + } + bool DeviceCreator::FindDevice(VkPhysicalDevice& device) + { + pmr::vector available_devices{FramePool()}; + instance.EnumerateAvailablePhysicalDevices(available_devices); + for (int i = 0, size = available_devices.size(); i < size; i++) + { + device = available_devices[i]; + if (!CheckProperty(device))continue; + if (!CheckExtension(device))continue; +#ifdef Z_RENDER_DEBUG + if (!CheckLayer(device))continue; +#endif // Z_RENDER_DEBUG + return true; + } + return false; + } + void DeviceCreator::QueueCreateInfos(pmr::vector& queue_create_infos, pmr::vector>& queue_prioritie, pmr::vector& queue_families) + { + uint32_t size = queue_families.size(); + for (uint32_t i = 0; i < size; i++) { + VkDeviceQueueCreateInfo queueCreateInfo{}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = i; + queueCreateInfo.queueCount = 0; + queue_create_infos.push_back(queueCreateInfo); + queue_prioritie.emplace_back(pmr::vector{FramePool()}); + } + uint32_t max_value = 1; + for (auto& queue : desiredQueues) { + uint32_t index = -1; + bool bFind = false; + for (uint32_t i = 0; i < size; i++) { + auto family = queue_families[i]; + if ((family.queueFlags & queue.flag) == queue.flag) { + index = i; + if (queue_create_infos[i].queueCount < max_value * family.queueCount) { + bFind = true; + break; + } + } + } + if (index != -1 && queue_create_infos[index].queueCount < queue_families[index].queueCount) { + queue.queueFamilyIndex = index; + queue_create_infos[index].queueCount++; + queue_prioritie[index].push_back(queue.prioritie); + } + if (!bFind) + max_value++; + } + auto it = queue_create_infos.begin(); + for (uint32_t i = 0; i < size; i++) { + if (it->queueCount == 0) { + it = queue_create_infos.erase(it); + } + else { + it->pQueuePriorities = queue_prioritie[i].data(); + it++; + } + } + } + pmr::vector DeviceCreator::EnabledExtensionNames() + { + pmr::vector _extension; + for (int i = 0, l = desiredExtensions.size(); i < l; i++) { + _extension.push_back(desiredExtensions[i].c_str()); + } + return _extension; + } + void DeviceCreator::EnableDeviceFeatures() + { + desiredPhysicalDeviceFeatures.independentBlend = true; + desiredPhysicalDeviceFeatures.depthClamp = true; + desiredPhysicalDeviceFeatures.geometryShader = VK_TRUE; + } + VkPhysicalDeviceFeatures2 DeviceCreator::GetDeviceFeature2() + { + // 明确设备要使用的功能特性 + VkPhysicalDeviceFeatures2 deviceFeatures = {}; + deviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + // 启用对各向异性采样的支持 + deviceFeatures.features.samplerAnisotropy = VK_TRUE; + deviceFeatures.features.geometryShader = VK_TRUE; + deviceFeatures.features.sampleRateShading = VK_TRUE; + deviceFeatures.features.shaderInt64 = VK_TRUE; + return deviceFeatures; + } + VkPhysicalDeviceVulkan12Features DeviceCreator::GetVulkan12Features() + { + // 添加Vulkan 1.2的特性 + VkPhysicalDeviceVulkan12Features deviceVulkan12Features = {}; + deviceVulkan12Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; + // 启用对Device Address的支持 + deviceVulkan12Features.bufferDeviceAddress = VK_TRUE; + deviceVulkan12Features.runtimeDescriptorArray = VK_TRUE; + deviceVulkan12Features.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; + deviceVulkan12Features.hostQueryReset = VK_TRUE; + deviceVulkan12Features.pNext = nullptr; + return deviceVulkan12Features; + } +#ifdef Z_RENDER_DEBUG + void DeviceCreator::AddLayer(string_view layerName) + { + desiredLayers.push_back(pmr::string{ layerName , FramePool()}); + } + bool DeviceCreator::CheckLayer(const VkPhysicalDevice device) + { + uint32_t layerCount = 0; + vkEnumerateDeviceLayerProperties(device, &layerCount, nullptr); + pmr::vector availableLayers{FramePool()}; + availableLayers.resize(layerCount); + vkEnumerateDeviceLayerProperties(device, &layerCount, availableLayers.data()); + for (const auto& desiredLayer : desiredLayers) + { + bool find = false; + for (const auto& availableLayer : availableLayers) + { + if (strcmp(availableLayer.layerName, desiredLayer.c_str()) == 0) + { + find = true; + break; + } + } + if (!find)return false; + } + return true; + } + pmr::vector DeviceCreator::EnabledLayerNames() + { + pmr::vector _extension{FramePool()}; + for (int i = 0, l = desiredLayers.size(); i < l; i++) { + _extension.push_back(desiredLayers[i].c_str()); + } + return _extension; + } +#endif // Z_RENDER_DEBUG + bool DeviceCreator::CheckAvailableQueueFamilies(VkPhysicalDevice physical_device, pmr::vector& queue_families) + { + uint32_t queue_families_count = 0; + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_families_count, nullptr); + if (queue_families_count == 0) { + zlog::error("Could not get the number of queue families."); + return false; + } + queue_families.resize(queue_families_count); + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_families_count, queue_families.data()); + if (queue_families_count == 0) { + zlog::error("Could not acquire properties of queue families."); + return false; + } + return true; + } +} diff --git a/engine/modules/render/vulkan/src/wrapper/instance.cpp b/engine/modules/render/vulkan/src/wrapper/instance.cpp index e69de29..4434cfb 100644 --- a/engine/modules/render/vulkan/src/wrapper/instance.cpp +++ b/engine/modules/render/vulkan/src/wrapper/instance.cpp @@ -0,0 +1,73 @@ +#include "vkn/wrapper/instance.h" +#include "vkn/wrapper/instance_create.h" +#include "zlog.h" +namespace vkn { + Instance::Instance(InstanceCreator& Creator) + { + VkResult res = volkInitialize(); + if (res != VK_SUCCESS) + zlog::error("Could not initialize volk!"); + VkApplicationInfo application_info = { + VK_STRUCTURE_TYPE_APPLICATION_INFO, // VkStructureType sType + nullptr, // const void * pNext + Creator.appName.c_str(), // const char * pApplicationName + Creator.appVersion, // uint32_t applicationVersion + Creator.engineName.c_str(), // const char * pEngineName + Creator.engineVersion, // uint32_t engineVersion + Creator.apiVersion // uint32_t apiVersion + }; +#ifdef Z_RENDER_DEBUG + Creator.AddDebugExtension(); +#endif // Z_RENDER_DEBUG + Creator.AddWindowExtension(); + Creator.AddInstanceExtension(); + auto extensions = Creator.EnabledExtensionNames(); + auto layers = Creator.EnabledLayerNames();; + VkInstanceCreateInfo instance_create_info = { + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // VkStructureType sType + nullptr, // const void * pNext + 0, // VkInstanceCreateFlags flags + &application_info, // const VkApplicationInfo * pApplicationInfo + static_cast(layers.size()), // uint32_t enabledLayerCount + layers.data(), // const char * const * ppEnabledLayerNames + static_cast(extensions.size()), // uint32_t enabledExtensionCount + extensions.data() // const char * const * ppEnabledExtensionNames + }; +#ifdef Z_RENDER_DEBUG + VkDebugUtilsMessengerCreateInfoEXT debugInfo = Creator.DebugUtilsLayerNext(); + instance_create_info.pNext = &debugInfo; +#endif + VkResult result = vkCreateInstance(&instance_create_info, nullptr, &mPtr); + if (result != VK_SUCCESS) { + zlog::error("Failed to create instance."); + } + volkLoadInstanceOnly(mPtr); + } + bool Instance::EnumerateAvailablePhysicalDevices(pmr::vector& available_devices) + { + uint32_t devices_count = 0; + VkResult result = VK_SUCCESS; + + result = vkEnumeratePhysicalDevices(mPtr, &devices_count, nullptr); + if ((result != VK_SUCCESS) || + (devices_count == 0)) { + zlog::error("Could not get the number of available physical devices."); + return false; + } + + available_devices.resize(devices_count); + result = vkEnumeratePhysicalDevices(mPtr, &devices_count, available_devices.data()); + if ((result != VK_SUCCESS) || + (devices_count == 0)) { + zlog::error("Could not enumerate physical devices."); + return false; + } + + return true; + } + VKAPI_ATTR VkBool32 VKAPI_CALL Instance::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void*) + { + zlog::error("validation layer: {}", pCallbackData->pMessage); + return VK_FALSE; + } +} diff --git a/engine/modules/render/vulkan/src/wrapper/instance_create.cpp b/engine/modules/render/vulkan/src/wrapper/instance_create.cpp new file mode 100644 index 0000000..333de3a --- /dev/null +++ b/engine/modules/render/vulkan/src/wrapper/instance_create.cpp @@ -0,0 +1,165 @@ +#include "vkn/wrapper/instance_create.h" +#include "vkn/wrapper/instance.h" +#include "zlog.h" +namespace vkn { + VkDebugUtilsMessengerCreateInfoEXT InstanceCreator::DebugUtilsLayerNext() + { + VkDebugUtilsMessengerCreateInfoEXT createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + createInfo.messageSeverity = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + createInfo.messageType = + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + createInfo.pfnUserCallback = debugCallback; + return createInfo; + } + InstanceCreator::InstanceCreator() + : desiredExtensions(FramePool()), desiredLayers(FramePool()) + , appName("Vulkan Application") + , appVersion(VK_API_VERSION_1_3) + , engineName("zengine") + , engineVersion(VK_API_VERSION_1_3) + , apiVersion(VK_API_VERSION_1_3) +#ifdef Z_RENDER_DEBUG + , messageSeverity(VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) + , messageType(VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) + , debugCallback(Instance::DebugCallback) +#endif + { + + } + void InstanceCreator::AddExtension(string_view extensionName) + { + desiredExtensions.push_back(pmr::string{ extensionName, FramePool() }); + } + void InstanceCreator::AddLayer(string_view layerName) + { + desiredLayers.push_back(pmr::string{ layerName, FramePool() }); + } + void InstanceCreator::AddWindowExtension() + { +#if defined(__ANDROID__) + AddExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); +#elif defined(__linux__) && defined(FILAMENT_SUPPORTS_WAYLAND) + AddExtension(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); +#elif defined(LINUX_OR_FREEBSD) && defined(FILAMENT_SUPPORTS_X11) + #if defined(FILAMENT_SUPPORTS_XCB) + AddExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME); + #endif + #if defined(FILAMENT_SUPPORTS_XLIB) + AddExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); + #endif +#elif defined(WIN32) + AddExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); +#endif + } + void InstanceCreator::AddInstanceExtension() + { + AddExtension(VK_KHR_SURFACE_EXTENSION_NAME); + AddExtension(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + AddExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + } +#ifdef Z_RENDER_DEBUG + void InstanceCreator::AddDebugExtension() + { + AddLayer("VK_LAYER_KHRONOS_validation"); + AddExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + AddExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + } +#endif // Z_RENDER_DEBUG + pmr::vector InstanceCreator::EnabledExtensionNames() + { + pmr::vector available_extensions{ FramePool() }; + pmr::vector _extension{ FramePool() }; + if (!CheckAvailableInstanceExtensions(available_extensions)) { + return _extension; + } + for (int i = 0, l = desiredExtensions.size(); i < l; i++) { + if (IsExtensionSupported(available_extensions, desiredExtensions[i].c_str())) { + _extension.push_back(desiredExtensions[i].c_str()); + } + else { + zlog::error("cann't support extension: {}", desiredExtensions[i].c_str()); + } + } + return _extension; + } + pmr::vector InstanceCreator::EnabledLayerNames() + { + pmr::vector available_layers{ FramePool() }; + pmr::vector _layers{ FramePool() }; + if (!CheckAvailableInstanceLayers(available_layers)) { + return _layers; + } + for (int i = 0, l = desiredLayers.size(); i < l; i++) { + if (IsLayerSupported(available_layers, desiredLayers[i].c_str())) { + _layers.push_back(desiredLayers[i].c_str()); + } + else { + zlog::error("Could not load instance-level Vulkan function named: {}", desiredLayers[i].c_str()); + } + } + return _layers; + } + bool InstanceCreator::CheckAvailableInstanceExtensions(pmr::vector& available_extensions) + { + uint32_t extensions_count = 0; + VkResult result = VK_SUCCESS; + + result = vkEnumerateInstanceExtensionProperties(nullptr, &extensions_count, nullptr); + if ((result != VK_SUCCESS) || + (extensions_count == 0)) { + zlog::error("Could not get the number of instance extensions."); + return false; + } + + available_extensions.resize(extensions_count); + result = vkEnumerateInstanceExtensionProperties(nullptr, &extensions_count, available_extensions.data()); + if ((result != VK_SUCCESS) || + (extensions_count == 0)) { + zlog::error("Could not enumerate instance extensions."); + return false; + } + return true; + } + bool InstanceCreator::CheckAvailableInstanceLayers(pmr::vector& available_layers) + { + uint32_t extensions_count = 0; + VkResult result = VK_SUCCESS; + + result = vkEnumerateInstanceLayerProperties(&extensions_count, nullptr); + if ((result != VK_SUCCESS) || + (extensions_count == 0)) { + zlog::error("Could not get the number of instance layers."); + return false; + } + + available_layers.resize(extensions_count); + result = vkEnumerateInstanceLayerProperties(&extensions_count, available_layers.data()); + if ((result != VK_SUCCESS) || + (extensions_count == 0)) { + zlog::error("Could not enumerate instance layers."); + return false; + } + + return true; + } + bool InstanceCreator::IsExtensionSupported(pmr::vector const& available_extensions, char const* const extension) + { + for (auto& available_extension : available_extensions) { + if (strstr(available_extension.extensionName, extension)) { + return true; + } + } + return false; + } + bool InstanceCreator::IsLayerSupported(pmr::vector const& available_layers, char const* const layer) + { + for (auto& available_layer : available_layers) { + if (strstr(available_layer.layerName, layer)) { + return true; + } + } + return false; + } +} diff --git a/engine/modules/render/vulkan/src/wrapper/queue.cpp b/engine/modules/render/vulkan/src/wrapper/queue.cpp new file mode 100644 index 0000000..d8c11b1 --- /dev/null +++ b/engine/modules/render/vulkan/src/wrapper/queue.cpp @@ -0,0 +1,12 @@ +#include "vkn/wrapper/queue.h" +namespace vkn { + const Name Queue::TransferQueue = "transfer"; + const Name Queue::RenderQueue = "render" ; + const Name Queue::ComputeQueue = "computer"; + const Name Queue::PresentQueue = "present" ; + Queue::Queue(Name name, uint32_t queueFamilyIndex, VkQueue queue) + : mName(name) + { + + } +} \ No newline at end of file diff --git a/engine/modules/render/vulkan/xmake.lua b/engine/modules/render/vulkan/xmake.lua index 7a37960..a0c8b98 100644 --- a/engine/modules/render/vulkan/xmake.lua +++ b/engine/modules/render/vulkan/xmake.lua @@ -2,4 +2,13 @@ shared_module("vulkan","engine") add_headerfiles("include/**.h") add_files("src/**.cpp", "include/volk/volk.c") add_packages("vulkansdk", {public = true}) - add_dependency("engine", {public = true}) \ No newline at end of file + add_dependency("engine", {public = true}) + on_load(function (target) + if is_plat("windows") then + target:add("defines", "VK_USE_PLATFORM_WIN32_KHR=1") + elseif is_plat("linux") then + target:add("defines", "VK_USE_PLATFORM_XLIB_KHR=1") + elseif is_plat("macosx") then + target:add("defines", "VK_USE_PLATFORM_MACOS_MVK=1") + end + end) \ No newline at end of file diff --git a/game/zworld/src/zworld.cpp b/game/zworld/src/zworld.cpp index 0891cca..c962bb9 100644 --- a/game/zworld/src/zworld.cpp +++ b/game/zworld/src/zworld.cpp @@ -6,8 +6,8 @@ using namespace api; void ZWorldModule::OnLoad(int argc, char** argv) { // 创建窗口 - new (GlobalPool()) vkn::VulkanWindow(&SDL_CreateWindow, { "zengine" }, 1080, 720); - new (GlobalPool()) vkn::VulkanAPI(); + new vkn::VulkanWindow(&SDL_CreateWindow, { "zengine" }, 1080, 720); + new vkn::VulkanAPI(); } void ZWorldModule::OnUnload()