diff --git a/engine/assets/shader/simple.vert b/engine/assets/shader/simple.vert index c8d3930..9bc5b28 100644 --- a/engine/assets/shader/simple.vert +++ b/engine/assets/shader/simple.vert @@ -1,11 +1,10 @@ #version 450 layout (location = 0) in vec3 iPos; -layout (location = 1) in vec2 iTex; layout (location = 0) out vec4 vColor; void main() { - gl_Position = vec4(iPos.x, iPos.y, iTex.x, 1.0); - vColor = vec4(gl_Position.x, gl_Position.y, gl_Position.z, 1.0); + gl_Position = vec4(iPos.x, iPos.y, iPos.z, 1.0); + vColor = vec4(1.0, 0.0, 0.0, 1.0); } diff --git a/engine/modules/engine/render/impl/renderapi_impl.inl b/engine/modules/engine/render/impl/renderapi_impl.inl index d678053..e37a552 100644 --- a/engine/modules/engine/render/impl/renderapi_impl.inl +++ b/engine/modules/engine/render/impl/renderapi_impl.inl @@ -5,6 +5,7 @@ namespace api { IMPLEMENT_STATIC_MODULE(RENDER_API, RenderModule, render); void RenderAPI::RenderView(FRenderView& view) { + view.context = &context; graph.Compile(); graph.Execute(view); graph.Clear(); @@ -22,6 +23,6 @@ namespace api { } RenderAPI::~RenderAPI() { - delete& context; + } } \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/asset/material.h b/engine/modules/engine/render/include/render/asset/material.h index 4893ccd..ec0177b 100644 --- a/engine/modules/engine/render/include/render/asset/material.h +++ b/engine/modules/engine/render/include/render/asset/material.h @@ -7,6 +7,7 @@ namespace api { friend class Scene; public: + Material(RscHandle shader) : Material() { mShader = shader; }; Material(); ~Material(); void BeginLoad() { diff --git a/engine/modules/engine/render/include/render/asset/vertex.h b/engine/modules/engine/render/include/render/asset/vertex.h index b05da7c..6b2193f 100644 --- a/engine/modules/engine/render/include/render/asset/vertex.h +++ b/engine/modules/engine/render/include/render/asset/vertex.h @@ -9,33 +9,33 @@ namespace api { template concept Vertexs = requires {std::is_base_of_v; }; struct PosVertex : public Vertex { - //UPROPERTY_gl({}, glVertexMeta{ 3, GL_FLOAT, GL_FALSE }) + 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_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_gl({}, glVertexMeta{ 2, GL_FLOAT, GL_FALSE }) UPROPERTY_vk() Vector2 TexCoords = {}; - //UPROPERTY_gl({}, glVertexMeta{ 3, GL_FLOAT, GL_FALSE }) + 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_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_gl({}, glVertexMeta{ 2, GL_FLOAT, GL_FALSE }) UPROPERTY_vk() Vector2 TexCoords = {}; - //UPROPERTY_gl({}, glVertexMeta{ 3, GL_FLOAT, GL_FALSE }) + UPROPERTY_gl({}, glVertexMeta{ 3, GL_FLOAT, GL_FALSE }) UPROPERTY_vk() Vector3 Normal = {}; - //UPROPERTY_gl({}, glVertexMeta{ 3, GL_FLOAT, GL_FALSE }) + UPROPERTY_gl({}, glVertexMeta{ 3, GL_FLOAT, GL_FALSE }) UPROPERTY_vk() Vector3 Tangent = {}; // 骨骼蒙皮数据 diff --git a/engine/modules/engine/render/include/render/graph/type.h b/engine/modules/engine/render/include/render/graph/type.h index bfb5b8f..6d77aa0 100644 --- a/engine/modules/engine/render/include/render/graph/type.h +++ b/engine/modules/engine/render/include/render/graph/type.h @@ -4,8 +4,15 @@ #include "lemon/list_graph.h" #include namespace api { + struct RenderContext; struct ComputePassContext {}; - struct RenderPassContext {}; + struct RenderPassContext { + RenderContext* parent; + RenderPassContext(RenderContext* parent) : parent(parent) {}; + RenderContext* operator->() { + return parent; + } + }; struct CopyPassContext {}; class FrameGraph; diff --git a/engine/modules/engine/render/include/render/render_context.h b/engine/modules/engine/render/include/render/render_context.h index 8fae588..1a6c244 100644 --- a/engine/modules/engine/render/include/render/render_context.h +++ b/engine/modules/engine/render/include/render/render_context.h @@ -10,5 +10,11 @@ namespace api { TextureDesc surface; uint32_t frame{ 0 }; uint32_t presentFrame{ 0 }; + virtual void SetViewport(float x, float y, float width, float height, float min_depth, float max_depth) = 0; + virtual void SetScissor(uint32_t x, uint32_t y, uint32_t width, uint32_t height) = 0; + virtual void BindIndexBuffer(BufferDesc desc, uint32_t index_stride) = 0; + virtual void BindVertexBuffer(BufferDesc buffers) = 0; + virtual void BindVertexBuffers(uint32_t buffer_count, const BufferDesc* buffers, const uint32_t* offsets) = 0; + virtual void DrawIndexed(uint32_t index_count, uint32_t first_index, uint32_t first_vertex) = 0; }; } \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/type.h b/engine/modules/engine/render/include/render/type.h index 01a6d64..03df8da 100644 --- a/engine/modules/engine/render/include/render/type.h +++ b/engine/modules/engine/render/include/render/type.h @@ -67,7 +67,9 @@ namespace api { }; using ImagePtr = void*; using ImageViewPtr = void*; + using BufferPtr = void*; struct BufferDesc { + BufferPtr buffer; static BufferDesc Make() { return {}; } diff --git a/engine/modules/engine/render/src/graph/frame_graph.cpp b/engine/modules/engine/render/src/graph/frame_graph.cpp index e29caf3..ea4b6ca 100644 --- a/engine/modules/engine/render/src/graph/frame_graph.cpp +++ b/engine/modules/engine/render/src/graph/frame_graph.cpp @@ -88,7 +88,7 @@ namespace api { { ExecuteResourceBarriers(node); RenderAPI::Ptr()->BeginRenderPass(node); - RenderPassContext context{}; + RenderPassContext context{view.context}; std::get(node->executor)(*this, context); RenderAPI::Ptr()->EndRenderPass(node); } diff --git a/engine/modules/engine/render/src/pass/demo_pass.cpp b/engine/modules/engine/render/src/pass/demo_pass.cpp index 0efc8bd..7e2259f 100644 --- a/engine/modules/engine/render/src/pass/demo_pass.cpp +++ b/engine/modules/engine/render/src/pass/demo_pass.cpp @@ -3,18 +3,32 @@ #include "render/asset/material.h" #include "render/renderapi.h" #include "asset/resource_system.h" +#include "render/asset/vertex.h" +#include "render/asset/mesh.h" namespace api { + static RscHandle material; + static RscHandle shader; + static RscHandle mesh; bool DemoPass::Setup(FrameGraph& graph, FrameGraph::RenderPassBuilder& builder) { - static RscHandle shader; if (!shader) { shader = ResourceSystem::Ptr()->LoadEmplaceResource(); shader->Name("api::PosVertex"); - auto vert = ResourceSystem::Ptr()->Load("/engine/assets/shader/simple.frag"); + auto vert = ResourceSystem::Ptr()->Load("/engine/assets/shader/simple.vert"); auto frag = ResourceSystem::Ptr()->Load("/engine/assets/shader/simple.frag"); shader->SetVertHandle(vert); shader->SetFragHandle(frag); RenderAPI::Ptr()->LoadShader(*shader); + vector vertices = { + {.Position = { 0.0f, -0.5f, 0.f}}, // 底部顶点,红色 + {.Position = { 0.5f, 0.5f, 0.f}}, // 右上顶点,绿色 + {.Position = {-0.5f, 0.5f, 0.f}} // 左上顶点,蓝色 + }; + vector indices = {0, 1, 2}; + mesh = ResourceSystem::Ptr()->LoadEmplaceResource(vertices, indices); + material = ResourceSystem::Ptr()->LoadEmplaceResource(shader); + mesh->SetMaterial(material); + RenderAPI::Ptr()->SetStaticMesh(*mesh); } AttachmentDesc surface{}; surface.FromTexture(graph.mSurface); @@ -29,8 +43,11 @@ namespace api { .Present(edge, edge.targetState); return false; } - void DemoPass::Execute(FrameGraph&, RenderPassContext&) + void DemoPass::Execute(FrameGraph& graph, RenderPassContext& ctx) { - + auto& surface = graph.mSurface; + ctx->SetViewport(0.0f, 0.0f,(float)surface.width,(float)surface.height, 0.f, 1.f); + ctx->SetScissor(0, 0, surface.width, surface.height); + RenderAPI::Ptr()->DrawStaticMesh(*mesh); } } diff --git a/engine/modules/engine/zlib/include/pmr/frame_allocator.inl b/engine/modules/engine/zlib/include/pmr/frame_allocator.inl index 5cab366..bccb554 100644 --- a/engine/modules/engine/zlib/include/pmr/frame_allocator.inl +++ b/engine/modules/engine/zlib/include/pmr/frame_allocator.inl @@ -11,6 +11,13 @@ namespace pmr { { size_t space = capacity - offset; void* ptr = buffer + offset; + if (bytes > capacity) { + if (std::align(alignment, bytes, ptr, space)) { + offset = capacity - space + bytes; + return ptr; + } + throw std::bad_alloc(); + } if (std::align(alignment, bytes, ptr, space)) { offset = capacity - space + bytes; return ptr; diff --git a/engine/modules/engine/zlib/include/refl/detail/name.h b/engine/modules/engine/zlib/include/refl/detail/name.h index 69a2ae4..54d76ba 100644 --- a/engine/modules/engine/zlib/include/refl/detail/name.h +++ b/engine/modules/engine/zlib/include/refl/detail/name.h @@ -6,7 +6,7 @@ namespace refl { struct TStr { std::array value{}; // 确切长度的字符数组,不依赖 '\0' constexpr TStr() {}; - constexpr TStr(const char(&data)[N]) { + constexpr TStr(const char(&data)[N + 1]) { std::copy_n(data, N, value.begin()); } @@ -21,7 +21,7 @@ namespace refl { }; template - TStr(const char(&)[N]) -> TStr; + TStr(const char(&)[N]) -> TStr; template constexpr auto value_name() noexcept; diff --git a/engine/modules/engine/zlib/include/refl/detail/name.inl b/engine/modules/engine/zlib/include/refl/detail/name.inl index f01224e..e48d082 100644 --- a/engine/modules/engine/zlib/include/refl/detail/name.inl +++ b/engine/modules/engine/zlib/include/refl/detail/name.inl @@ -33,7 +33,7 @@ namespace refl { } template constexpr auto num_name() { - char data[Digits]; + char data[Digits + 1]; int n = N; for (int i = Digits - 1; i >= 0; --i) { data[i] = static_cast('0' + n % 10); @@ -82,6 +82,18 @@ namespace refl { } } } + template + constexpr auto concat_seq(Args1 args1, Args&&... args) { + if constexpr (sizeof...(Args) == 0) { + return args1; + } + else if constexpr (sizeof...(Args) == 1) { + return detail::concat(args1, args...); + } + else { + return detail::concat(args1, concat_seq(args...)); + } + } template constexpr auto meta_name() noexcept { if constexpr (std::is_same_v) { @@ -90,7 +102,24 @@ namespace refl { else if constexpr (std::is_arithmetic_v) { constexpr auto prefix = detail::num_prefix_name(); constexpr auto bit = detail::num_name<8 * sizeof(T)>(); - return detail::concat(prefix, bit); + return concat_seq(prefix, bit); + } + else if constexpr (std::is_array_v) { + constexpr auto r = std::rank_v; + constexpr auto ex = std::extent_v; + if constexpr (r == 1) { + if constexpr (ex == 0) + return concat_seq(TStr{"[]{"}, meta_name>(), TStr{"}"}); + else + return concat_seq(TStr{"["}, detail::num_name(), TStr{"]{"}, meta_name>(), TStr{"}"}); + } + else { // r > 1 + static_assert(r > 1); + if constexpr (ex == 0) + return concat_seq(TStr{"[]"}, type_name>()); + else + return concat_seq(TStr{"["}, detail::num_name(), TStr{"]"}, meta_name>()); + } } else { return detail::raw_meta_name(); diff --git a/engine/modules/engine/zlib/include/refl/detail/type.h b/engine/modules/engine/zlib/include/refl/detail/type.h index 4ba74c0..8af64f9 100644 --- a/engine/modules/engine/zlib/include/refl/detail/type.h +++ b/engine/modules/engine/zlib/include/refl/detail/type.h @@ -105,6 +105,10 @@ namespace refl { template using args_type_t = detail::args_type>::type; }; +namespace gen { + template + struct MetaImpl; +} namespace refl { template struct Meta {}; @@ -112,6 +116,12 @@ namespace refl { template concept is_meta_v = requires { typename Meta::Impl; }; + template + concept is_metas_v = requires() { Meta::MetaList(); }; + + template + concept have_meta_impl_v = requires() { typename gen::MetaImpl::T; }; + template concept has_parent_v = requires { typename Meta::Parent; }; @@ -124,5 +134,6 @@ namespace refl { struct UClass; template const UClass* meta_info(); + const UClass* find_info(Name name, size_t hash); constexpr uint32_t MAX_ARGS_LENGTH = 10; } \ No newline at end of file diff --git a/engine/modules/engine/zlib/include/refl/detail/uclass.h b/engine/modules/engine/zlib/include/refl/detail/uclass.h index 23c58ff..473dbd9 100644 --- a/engine/modules/engine/zlib/include/refl/detail/uclass.h +++ b/engine/modules/engine/zlib/include/refl/detail/uclass.h @@ -73,8 +73,6 @@ namespace refl { } //class using GetFields_t = span(*)(const UClass*, EFieldFind find, Name name); - //class meta - using GetMeta_t = const UClass* (*)(Name); //function using GetParams_t = span(*)(const UClass*); //function args @@ -85,9 +83,6 @@ namespace refl { void AddGetFields(GetFields_t func) { Add(string_hash("GetFields"), (void*)func); } - void AddGetMeta(GetMeta_t func) { - Add(string_hash("GetMeta"), (void*)func); - } void AddGetParams(GetParams_t func) { Add(string_hash("GetParams"), (void*)func); } @@ -101,7 +96,6 @@ namespace refl { Add(string_hash("Destruct"), (void*)func); } GetFields_t GetFields() const { return (GetFields_t) Find(string_hash("GetFields")); } - GetMeta_t GetMeta() const { return (GetMeta_t) Find(string_hash("GetMeta")); } GetParams_t GetParams() const { return (GetParams_t) Find(string_hash("GetParams")); } Call_t Call() const { return (Call_t) Find(string_hash("Call")); } Construct_t Construct() const { return (Construct_t) Find(string_hash("Construct")); } @@ -111,7 +105,7 @@ namespace refl { public: Name name; uint32_t size; - uint32_t flag{0}; + uint32_t flag : 16{0}; const UClass* parent; vtable_uclass vtable; UClass(const UClass*) = delete; @@ -145,12 +139,8 @@ namespace refl { } return {}; } - const UClass* GetMeta(Name name)const { - auto func = vtable.GetMeta(); - if (func) { - return func(name); - } - return {}; + const UClass* GetMeta(size_t hash)const { + return find_info(name, hash); } bool IsChildOf(const UClass* cls, bool bthis = false) const { const UClass* _parent = bthis ? this : parent; diff --git a/engine/modules/engine/zlib/include/refl/detail/uclass.inl b/engine/modules/engine/zlib/include/refl/detail/uclass.inl index 4f68e9b..bc90c83 100644 --- a/engine/modules/engine/zlib/include/refl/detail/uclass.inl +++ b/engine/modules/engine/zlib/include/refl/detail/uclass.inl @@ -2,8 +2,6 @@ #include "name.h" #include "type.h" namespace refl { - template - concept is_metas_v = requires(const Name & name) { Meta::GetMeta(name); }; template class UClass_Auto : public UClass { public: @@ -26,9 +24,6 @@ namespace refl { else { vtable.AddConstruct(&UClass::Construct); vtable.AddDestruct(&UClass::Destruct); - if constexpr (is_metas_v) { - vtable.AddGetMeta(&Meta::GetMeta); - } } } }; @@ -173,9 +168,6 @@ namespace refl { if constexpr (has_parent_v) { parent = meta_info>(); } - if constexpr (is_metas_v) { - vtable.AddGetMeta(&Meta::GetMeta); - } vtable.AddGetFields(&UClass_Meta::GetFields); vtable.AddConstruct(&UClass::Construct); } @@ -256,8 +248,15 @@ namespace refl { return new(MetaGlobalPool()) UClass_Container{}; } }; + struct MetaClasses { + size_t hash{ 0 }; + const UClass* cls{nullptr}; + MetaClasses* next{ nullptr }; + }; using __tClassTable = table; UNIQUER_INLINE(__tClassTable, ClassTable, "refl::ClassTable") + using __tMetaClassTable = table; + UNIQUER_INLINE(__tMetaClassTable, MetaClassTable, "refl::MetaClassTable") inline const UClass* find_info(Name name) { auto& ClassTable = UNIQUER_VAL(ClassTable); if (auto it = ClassTable.find(name); it != ClassTable.end()) { @@ -265,6 +264,19 @@ namespace refl { } return nullptr; } + inline const UClass* find_info(Name name, size_t hash) { + auto& MetaClassTable = UNIQUER_VAL(MetaClassTable); + if (auto it = MetaClassTable.find(name); it != MetaClassTable.end()) { + auto meta = &it->second; + while (meta) { + if (meta->hash == hash) { + return meta->cls; + } + meta = meta->next; + } + } + return nullptr; + } template inline const UClass* meta_info() { @@ -287,4 +299,46 @@ namespace refl { ClassTable[name.view()] = cls; return cls; } + template + inline const UClass* meta_info() + { + if constexpr (have_meta_impl_v) { + constexpr auto name = meta_name(); + const UClass* cls = find_info(name.view(), hash); + if (cls) { + return cls; + } + cls = new(MetaGlobalPool()) UClass_Meta>{}; + auto& MetaClassTable = UNIQUER_VAL(MetaClassTable); + if (auto it = MetaClassTable.find(name.view()); it != MetaClassTable.end()) { + auto meta = &it->second; + while (meta) { + if (!meta->next) { + meta->next = new (MetaGlobalPool()) MetaClasses{ hash, cls }; + break; + } + meta = meta->next; + } + } + else { + MetaClassTable.emplace(name.view(), MetaClasses{hash, cls}); + } + return cls; + } + else { + return meta_info(); + } + } + template + inline void register_meta() + { + if constexpr (is_metas_v) { + constexpr auto metaList = Meta::MetaList(); + meta_info (); + if constexpr (index + 1 < metaList.size()) { + register_meta(); + } + } + meta_info(); + } } \ No newline at end of file diff --git a/engine/modules/engine/zlib/include/std/thread.h b/engine/modules/engine/zlib/include/std/thread.h index 8e3007a..8df226e 100644 --- a/engine/modules/engine/zlib/include/std/thread.h +++ b/engine/modules/engine/zlib/include/std/thread.h @@ -10,9 +10,10 @@ namespace zstd{ channel mChannel; void WorkLoop() { mThread.detach(); + Loop(); } void Loop() { - Worker* worker = dynamic_cast(this); + Worker* worker = (Worker*)(this); worker->Loop(); } public: diff --git a/engine/modules/render/vulkan/include/vkn/thread/worker.h b/engine/modules/render/vulkan/include/vkn/thread/worker.h index 841a5ed..2f7f63a 100644 --- a/engine/modules/render/vulkan/include/vkn/thread/worker.h +++ b/engine/modules/render/vulkan/include/vkn/thread/worker.h @@ -2,6 +2,7 @@ #include "std/thread.h" #include "vkn/wrapper/commandpool.h" #include "vkn/wrapper/queue.h" +#include "vkn/wrapper/device.h" namespace vkn { using zstd::channel; template @@ -12,6 +13,7 @@ namespace vkn { Queue& mQueue; CommandPool mCommandPool; CommandBuffer mImmediateExeCmd; + VkFence mImmediateFence; public: ThreadWorker(Name name, Device& device, Queue& queue, VkCommandPoolCreateFlags queueFlags) : zstd::ThreadWorker(64) @@ -20,6 +22,7 @@ namespace vkn { , mQueue(queue) , mCommandPool(device, queueFlags, queue.QueueFamilyIndex()) , mImmediateExeCmd(mCommandPool.AllocateBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY)) + , mImmediateFence(device.CreateFence(VK_FENCE_CREATE_SIGNALED_BIT)) {} CommandPool& GetCommandPool() { return mCommandPool; diff --git a/engine/modules/render/vulkan/include/vkn/type.h b/engine/modules/render/vulkan/include/vkn/type.h index 1434bf2..1806676 100644 --- a/engine/modules/render/vulkan/include/vkn/type.h +++ b/engine/modules/render/vulkan/include/vkn/type.h @@ -28,6 +28,7 @@ namespace vkn { constexpr uint8_t MAX_SUPPORTED_RENDER_TARGET_COUNT = 8u; constexpr uint32_t SHADER_MODULE_COUNT = 2; constexpr uint32_t VERTEX_ATTRIBUTE_COUNT = 16; + constexpr uint32_t MAX_BUFFER_BIND_NUM = 16; struct MeshVAO { uint32_t indexCount = 0; // 索引数量 @@ -87,60 +88,6 @@ namespace vkn { uint16_t inputRate; uint32_t stride; }; - //! blending equation function - enum class BlendEquation : uint8_t { - ADD, //!< the fragment is added to the color buffer - SUBTRACT, //!< the fragment is subtracted from the color buffer - REVERSE_SUBTRACT, //!< the color buffer is subtracted from the fragment - MIN, //!< the min between the fragment and color buffer - MAX //!< the max between the fragment and color buffer - }; - //! comparison function for the depth / stencil sampler - enum class SamplerCompareFunc : uint8_t { - // don't change the enums values - LE = 0, //!< Less or equal - GE, //!< Greater or equal - L, //!< Strictly less than - G, //!< Strictly greater than - E, //!< Equal - NE, //!< Not equal - A, //!< Always. Depth / stencil testing is deactivated. - N //!< Never. The depth / stencil test always fails. - }; - // >>> depthBiasClamp, polygonMode, lineWidth - struct RasterState { - VkCullModeFlags cullMode : 2; - VkFrontFace frontFace : 2; - VkBool32 depthBiasEnable : 1; - VkBool32 blendEnable : 1; - VkBool32 depthWriteEnable : 1; - VkBool32 alphaToCoverageEnable : 1; - VkBlendFactor srcColorBlendFactor : 5; // offset = 1 byte - VkBlendFactor dstColorBlendFactor : 5; - VkBlendFactor srcAlphaBlendFactor : 5; - VkBlendFactor dstAlphaBlendFactor : 5; - VkColorComponentFlags colorWriteMask : 4; - uint8_t rasterizationSamples; // offset = 4 bytes - uint8_t colorTargetCount; // offset = 5 bytes - BlendEquation colorBlendOp : 4; // offset = 6 bytes - BlendEquation alphaBlendOp : 4; - SamplerCompareFunc depthCompareOp; // offset = 7 bytes - float depthBiasConstantFactor; // offset = 8 bytes - float depthBiasSlopeFactor; // offset = 12 bytes - }; - // The pipeline key is a POD that represents all currently bound states that form the immutable - // VkPipeline object. The size:offset comments below are expressed in bytes. - struct PipelineKey { // size : offset - VkShaderModule shaders[SHADER_MODULE_COUNT]; // 16 : 0 - VkRenderPass renderPass; // 8 : 16 - uint16_t topology; // 2 : 24 - uint16_t subpassIndex; // 2 : 26 - VertexInputAttributeDescription vertexAttributes[VERTEX_ATTRIBUTE_COUNT]; // 128 : 28 - VertexInputBindingDescription vertexBuffers[VERTEX_ATTRIBUTE_COUNT]; // 128 : 156 - RasterState rasterState; // 16 : 284 - uint32_t padding; // 4 : 300 - VkPipelineLayout layout; // 8 : 304 - }; struct VulkanPipeline { Name name; // For debug diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_api.h b/engine/modules/render/vulkan/include/vkn/vulkan_api.h index c728367..5ff5e2d 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_api.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_api.h @@ -1,8 +1,6 @@ #pragma once -#include "type.h" +#include "vulkan_context.h" #include "asset/res/guid.h" -#include "render/renderapi.h" -#include "wrapper/commandbuffer.h" #include "backend.h" namespace vkn { class Backend; @@ -13,12 +11,6 @@ namespace vkn { using api::Mesh; using api::Shader; using api::RenderPassNode; - struct VulkanContext : public api::RenderContext { - VkFence surfaceFence;; - VkSemaphore surfaceSemaphore; - VkSemaphore presentSemaphore; - CommandBuffer command; - }; class VULKAN_API VulkanAPI : public api::RenderAPI { private: VulkanWindow& window; diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_api_help.h b/engine/modules/render/vulkan/include/vkn/vulkan_api_help.h index 6a717d3..60cdee2 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_api_help.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_api_help.h @@ -20,6 +20,4 @@ namespace vkn { VkImageCreateFlags vkApiGetImageCreateFlag(TextureDimension dimension, uint32_t arraySize); VkSampleCountFlagBits vkApiGetSmpleCountFlag(SampleCount sample); - VkDescriptorSetLayout vkApiCreateDescriptorSetLayout(); - VkPipelineLayout vkApiCreatePipelineLayout(const pmr::vector& descriptorSetLayouts, const pmr::vector& pushConstantRanges); } \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_context.h b/engine/modules/render/vulkan/include/vkn/vulkan_context.h new file mode 100644 index 0000000..c11f23e --- /dev/null +++ b/engine/modules/render/vulkan/include/vkn/vulkan_context.h @@ -0,0 +1,20 @@ +#include "type.h" +#include "render/renderapi.h" +namespace vkn { + using api::BufferDesc; + struct VulkanContext : public api::RenderContext { + VkFence surfaceFence; + VkSemaphore surfaceSemaphore; + VkSemaphore presentSemaphore; + VkCommandBuffer command; + void SetScissor(uint32_t x, uint32_t y, uint32_t width, uint32_t height) override; + void SetViewport(float x, float y, float width, float height, float min_depth, float max_depth) override; + void BindIndexBuffer(BufferDesc desc, uint32_t index_stride) override; + void BindVertexBuffer(BufferDesc desc) override; + void BindVertexBuffers(uint32_t buffer_count, const BufferDesc* descs, const uint32_t* offsets)override; + void DrawIndexed(uint32_t index_count, uint32_t first_index, uint32_t first_vertex) override; + + void BeginRecord(VkCommandBufferUsageFlags flag); + void EndRecord(VkQueue queue); + }; +} \ 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 949705f..68c5d71 100644 --- a/engine/modules/render/vulkan/include/vkn/wrapper/device.h +++ b/engine/modules/render/vulkan/include/vkn/wrapper/device.h @@ -27,7 +27,7 @@ namespace vkn { VkFence PopFence(); void PushWaitFence(VkFence fence); VkSemaphore CreateSemaphore(); - VkShaderModule CreateShaderModule(pmr::vector code); - VkShaderModule CreateShaderModule(pmr::vector code); + VkShaderModule CreateShaderModule(const pmr::vector& code); + VkShaderModule CreateShaderModule(const pmr::vector& code); }; }; \ 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 f0f5ad8..bdd2485 100644 --- a/engine/modules/render/vulkan/src/backend.cpp +++ b/engine/modules/render/vulkan/src/backend.cpp @@ -24,8 +24,8 @@ namespace vkn { DeviceCreator deviceCreator = DeviceCreator{ *mInstance }; deviceCreator.AddWindowExtension(); - deviceCreator.AddQueue(Queue::TransferQueue,VkQueueFlagBits::VK_QUEUE_TRANSFER_BIT, 1.0); deviceCreator.AddQueue(Queue::RenderQueue, VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT, 1.0); + deviceCreator.AddQueue(Queue::TransferQueue, VkQueueFlagBits::VK_QUEUE_TRANSFER_BIT, 1.0); mDevice = new (GlobalPool()) Device(deviceCreator); Backend::TransferWorker = InitWorker(Queue::TransferQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); diff --git a/engine/modules/render/vulkan/src/loader/vulkan_glsl_loader.cpp b/engine/modules/render/vulkan/src/loader/vulkan_glsl_loader.cpp index 97c1a47..9806d9b 100644 --- a/engine/modules/render/vulkan/src/loader/vulkan_glsl_loader.cpp +++ b/engine/modules/render/vulkan/src/loader/vulkan_glsl_loader.cpp @@ -9,9 +9,9 @@ using namespace api; namespace vkn { void VulkanGlslLoader::Init() { - refl::meta_info(); - refl::meta_info(); - refl::meta_info(); + refl::register_meta(); + refl::register_meta(); + refl::register_meta(); ResourceSystem::Ptr()->RegisterLoader(".geom"); ResourceSystem::Ptr()->RegisterLoader(".frag"); ResourceSystem::Ptr()->RegisterLoader(".vert"); diff --git a/engine/modules/render/vulkan/src/thread/buffer_worker.cpp b/engine/modules/render/vulkan/src/thread/buffer_worker.cpp index 1f70a8b..9065f90 100644 --- a/engine/modules/render/vulkan/src/thread/buffer_worker.cpp +++ b/engine/modules/render/vulkan/src/thread/buffer_worker.cpp @@ -28,6 +28,7 @@ namespace vkn { { while (true) { Element elem = mChannel.acquire(); + mImmediateExeCmd.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); VkBufferCreateInfo bufferInfo = {}; bufferInfo.size = elem.size; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; @@ -59,6 +60,11 @@ namespace vkn { VkBufferCopy copyRegion = {}; copyRegion.size = elem.size; vkCmdCopyBuffer(mImmediateExeCmd.Ptr(), stagingBuffer, gpuBuffer, 1, ©Region); + mImmediateExeCmd.EndRecord(); + vkResetFences(mDevice.Ptr(), 1, &mImmediateFence); + mImmediateExeCmd.Submit(mQueue.Ptr(), mImmediateFence); + vkWaitForFences(mDevice.Ptr(), 1, &mImmediateFence, VK_TRUE, UINT64_MAX); + vkDestroyBuffer(mDevice.Ptr(), stagingBuffer, nullptr); } } } diff --git a/engine/modules/render/vulkan/src/vulkan_api.cpp b/engine/modules/render/vulkan/src/vulkan_api.cpp index 7edb526..3998b7d 100644 --- a/engine/modules/render/vulkan/src/vulkan_api.cpp +++ b/engine/modules/render/vulkan/src/vulkan_api.cpp @@ -74,7 +74,21 @@ namespace vkn { } void VulkanAPI::DrawStaticMesh(Mesh& mesh) { - + MeshVAO& vulkanVAO = MeshTable[mesh.GetGuid()]; + if (!vulkanVAO.indexBuffer || !vulkanVAO.vertexBuffer) { + return; + } + VulkanPipeline& pipeline = PipelineTable[mesh.GetShaderGuid()]; + VulkanContext& ctx = *(VulkanContext*)&context; + VkCommandBuffer ptr = ctx.command; + VkBuffer vertexBuffers[] = { vulkanVAO.vertexBuffer }; + VkDeviceSize offsets[] = { 0 }; + vkCmdBindVertexBuffers(ptr, 0, 1, vertexBuffers, offsets); + vkCmdBindIndexBuffer(ptr, vulkanVAO.indexBuffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdBindPipeline(ptr, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline); + if(pipeline.descriptorSet) + vkCmdBindDescriptorSets(ptr, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipelineLayout, 0, 1, &pipeline.descriptorSet, 0, VK_NULL_HANDLE); + vkCmdDrawIndexed(ptr, vulkanVAO.indexCount, 1, 0, 0, 0); } void VulkanAPI::LoadShader(Shader& shader) { @@ -95,7 +109,7 @@ namespace vkn { shaderStages.push_back(shaderStageInfo); } auto it = refl::find_info(shader.Name()); - auto meta = it->GetMeta("vkMeta"); + auto meta = it->GetMeta(string_hash("vkMeta")); // 设置顶点输入格式 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; VkVertexInputBindingDescription bindingDescription = {}; @@ -173,7 +187,8 @@ namespace vkn { multisampleInfo.alphaToOneEnable = VK_FALSE; RenderPassKey config{}; - config.colorFormat[0] = VK_FORMAT_R8G8B8A8_UNORM; + config.colorFormat[0] = VK_FORMAT_B8G8R8A8_SRGB; + config.samples = vkApiGetSmpleCountFlag(api::SAMPLE_COUNT_1); VkRenderPass renderpass = GetRenderPass(config); // Color Blend VkPipelineColorBlendAttachmentState colorBlendAttachment{}; @@ -205,8 +220,14 @@ namespace vkn { depthStencilInfo.stencilTestEnable = VK_FALSE; depthStencilInfo.front = {}; depthStencilInfo.back = {}; - auto descriptorSetLayout = vkApiCreateDescriptorSetLayout(); - auto pipelineLayout = vkApiCreatePipelineLayout({ descriptorSetLayout }, {}); + VkDescriptorSetLayout descriptorSetLayout{}; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 0; // 没有描述符集布局时可以设置为0 + pipelineLayoutInfo.pSetLayouts = nullptr; + VkPipelineLayout pipelineLayout; + if (vkCreatePipelineLayout(device.Ptr(), &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) + throw std::runtime_error("failed to create pipeline layout!"); VkGraphicsPipelineCreateInfo pipelineInfo{}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; @@ -239,7 +260,7 @@ namespace vkn { vulkan_pipeline.inUse = true; vulkan_pipeline.pipelineLayout = pipelineLayout; vulkan_pipeline.descriptorSetLayout = descriptorSetLayout; - vulkan_pipeline.descriptorSet = backend.GetPool().Allocate(descriptorSetLayout); + vulkan_pipeline.descriptorSet = descriptorSetLayout ? backend.GetPool().Allocate(descriptorSetLayout) : nullptr; } ImagePtr VulkanAPI::CreateTexture(TextureDesc desc) { @@ -304,27 +325,12 @@ namespace vkn { { VulkanContext& ctx = *(VulkanContext*)&context; window.Aquire(ctx); - ctx.command.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + ctx.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); } void VulkanAPI::EndFrame() { VulkanContext& ctx = *(VulkanContext*)&context; - ctx.command.EndRecord(); - VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; // 等待渲染阶段 - VkSemaphore waitSemaphores[] = { ctx.surfaceSemaphore }; - VkSemaphore signalSemaphores[] = { ctx.presentSemaphore };// 渲染完成信号量 - VkSubmitInfo submitInfo{}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &ctx.command.Ptr(); - - submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = waitSemaphores; - submitInfo.pWaitDstStageMask = waitStages; - - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = signalSemaphores; - vkQueueSubmit(Backend::RenderWorker->GetQueue().Ptr(), 1, &submitInfo, ctx.surfaceFence); + ctx.EndRecord(Backend::RenderWorker->GetQueue().Ptr()); window.Present(ctx); } void VulkanAPI::ExecuteResourceBarriers(const ResourceBarrierDesc& desc) { @@ -343,7 +349,7 @@ namespace vkn { if (dstStageMask == 0) { dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; } - vkCmdPipelineBarrier(ctx.command.Ptr(), srcStageMask, dstStageMask, 0, 0, NULL, 0, NULL, imageBarriers.size(), imageBarriers.data()); + vkCmdPipelineBarrier(ctx.command, srcStageMask, dstStageMask, 0, 0, NULL, 0, NULL, imageBarriers.size(), imageBarriers.data()); } void VulkanAPI::BeginRenderPass(RenderPassNode* node) { @@ -401,12 +407,12 @@ namespace vkn { .pClearValues = clearValues }; VulkanContext& ctx = *(VulkanContext*)&context; - vkCmdBeginRenderPass(ctx.command.Ptr(), &beginInfo, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBeginRenderPass(ctx.command, &beginInfo, VK_SUBPASS_CONTENTS_INLINE); } void VulkanAPI::EndRenderPass(RenderPassNode* node) { VulkanContext& ctx = *(VulkanContext*)&context; - vkCmdEndRenderPass(ctx.command.Ptr()); + vkCmdEndRenderPass(ctx.command); } VkRenderPass VulkanAPI::GetRenderPass(RenderPassKey& config) { auto it = RenderPassCache.find(config); diff --git a/engine/modules/render/vulkan/src/vulkan_api_help.cpp b/engine/modules/render/vulkan/src/vulkan_api_help.cpp index a506037..062c87e 100644 --- a/engine/modules/render/vulkan/src/vulkan_api_help.cpp +++ b/engine/modules/render/vulkan/src/vulkan_api_help.cpp @@ -233,12 +233,4 @@ namespace vkn { { return (VkSampleCountFlagBits)sample; } - VkDescriptorSetLayout vkApiCreateDescriptorSetLayout() - { - return VkDescriptorSetLayout{}; - } - VkPipelineLayout vkApiCreatePipelineLayout(const pmr::vector& descriptorSetLayouts, const pmr::vector& pushConstantRanges) - { - return VkPipelineLayout(); - } } \ No newline at end of file diff --git a/engine/modules/render/vulkan/src/vulkan_context.cpp b/engine/modules/render/vulkan/src/vulkan_context.cpp new file mode 100644 index 0000000..524520d --- /dev/null +++ b/engine/modules/render/vulkan/src/vulkan_context.cpp @@ -0,0 +1,79 @@ +#include "vkn/vulkan_context.h" +#include "vkn/backend.h" +namespace vkn { + void VulkanContext::SetScissor(uint32_t x, uint32_t y, uint32_t width, uint32_t height) + { + VkRect2D scissor = { + .offset{ .x = (int32_t)x, .y = (int32_t)y}, + .extent {.width = width,.height = height} + }; + vkCmdSetScissor(command, 0, 1, &scissor); + } + void VulkanContext::SetViewport(float x, float y, float width, float height, float min_depth, float max_depth) + { + VkViewport viewport = { + .x = x, + .y = y, + .width = width, + .height = height, + .minDepth = min_depth, + .maxDepth = max_depth + }; + vkCmdSetViewport(command, 0, 1, &viewport); + } + void VulkanContext::BindIndexBuffer(BufferDesc desc, uint32_t index_stride) + { + VkIndexType vk_index_type = + (sizeof(uint16_t) == index_stride) ? + VK_INDEX_TYPE_UINT16 : ((sizeof(uint8_t) == index_stride) ? VK_INDEX_TYPE_UINT8_EXT : VK_INDEX_TYPE_UINT32); + vkCmdBindIndexBuffer(command, (VkBuffer)desc.buffer, 0, vk_index_type); + } + void VulkanContext::BindVertexBuffer(BufferDesc desc) + { + VkBuffer vertexBuffers[] = { (VkBuffer)desc.buffer }; + VkDeviceSize offsets[] = { 0 }; + vkCmdBindVertexBuffers(command, 0, 1, vertexBuffers, offsets); + } + void VulkanContext::BindVertexBuffers(uint32_t buffer_count, const BufferDesc* descs, const uint32_t* offsets) + { + VkBuffer vkBuffers[MAX_BUFFER_BIND_NUM] = { 0 }; + VkDeviceSize vkOffsets[MAX_BUFFER_BIND_NUM] = { 0 }; + for (uint32_t i = 0; i < buffer_count; i++) { + vkBuffers[i] = (VkBuffer)descs[i].buffer; + vkOffsets[i] = offsets[i]; + } + vkCmdBindVertexBuffers(command, 0, buffer_count, vkBuffers, vkOffsets); + } + void VulkanContext::DrawIndexed(uint32_t index_count, uint32_t first_index, uint32_t first_vertex) + { + vkCmdDrawIndexed(command, index_count, 1, first_index, first_vertex, 0); + } + void VulkanContext::BeginRecord(VkCommandBufferUsageFlags flag) + { + VkCommandBufferBeginInfo beginInfo{ + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,//sType + nullptr, //pNext + flag //flags + }; + vkBeginCommandBuffer(command, &beginInfo); + } + void VulkanContext::EndRecord(VkQueue queue) + { + vkEndCommandBuffer(command); + VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; // 等待渲染阶段 + VkSemaphore waitSemaphores[] = { surfaceSemaphore }; + VkSemaphore signalSemaphores[] = { presentSemaphore };// 渲染完成信号量 + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &command; + + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = waitSemaphores; + submitInfo.pWaitDstStageMask = waitStages; + + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = signalSemaphores; + vkQueueSubmit(queue, 1, &submitInfo, surfaceFence); + } +} diff --git a/engine/modules/render/vulkan/src/wrapper/device.cpp b/engine/modules/render/vulkan/src/wrapper/device.cpp index 7c7430b..277b9f9 100644 --- a/engine/modules/render/vulkan/src/wrapper/device.cpp +++ b/engine/modules/render/vulkan/src/wrapper/device.cpp @@ -97,7 +97,7 @@ namespace vkn { VkResult result = vkCreateSemaphore(mPtr, &semaphoreInfo, nullptr, &semaphore); return semaphore; } - VkShaderModule Device::CreateShaderModule(pmr::vector code) + VkShaderModule Device::CreateShaderModule(const pmr::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; @@ -109,7 +109,7 @@ namespace vkn { VkResult result = vkCreateShaderModule(mPtr, &createInfo, nullptr, &module); return module; } - VkShaderModule Device::CreateShaderModule(pmr::vector code) + VkShaderModule Device::CreateShaderModule(const pmr::vector& code) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; diff --git a/engine/modules/render/vulkan/src/wrapper/device_create.cpp b/engine/modules/render/vulkan/src/wrapper/device_create.cpp index f09ed93..3968b93 100644 --- a/engine/modules/render/vulkan/src/wrapper/device_create.cpp +++ b/engine/modules/render/vulkan/src/wrapper/device_create.cpp @@ -93,7 +93,7 @@ namespace vkn { auto family = queue_families[i]; if ((family.queueFlags & queue.flag) == queue.flag) { index = i; - if (queue_create_infos[i].queueCount < max_value * family.queueCount) { + if (queue_create_infos[i].queueCount < max_value) { bFind = true; break; } diff --git a/engine/modules/render/vulkan/src/wrapper/queue.cpp b/engine/modules/render/vulkan/src/wrapper/queue.cpp index d70e54e..68b3f79 100644 --- a/engine/modules/render/vulkan/src/wrapper/queue.cpp +++ b/engine/modules/render/vulkan/src/wrapper/queue.cpp @@ -3,7 +3,7 @@ namespace vkn { const Name Queue::TransferQueue = "transfer"; const Name Queue::RenderQueue = "render" ; Queue::Queue(Name name, uint32_t queueFamilyIndex, VkQueue queue) - : mName(name) + : mName(name), mPtr(queue), mQueueFamilyIndex(queueFamilyIndex) { } diff --git a/game/zworld/editor/zworld_editor.cpp b/game/zworld/editor/zworld_editor.cpp index ad38859..5a07b26 100644 --- a/game/zworld/editor/zworld_editor.cpp +++ b/game/zworld/editor/zworld_editor.cpp @@ -9,12 +9,15 @@ using namespace std; using namespace refl; template void print_name() { + auto sf = refl::TStr{ "S" }; + auto sf2 = refl::TStr{ "void" }; auto aguid = meta_name(); auto bguid = aguid.view(); std::cout << bguid << std::endl; } int main() { - print_name(); + constexpr auto aa = refl::detail::num_name<32>(); + print_name(); print_name(); std::cout << "hello world" << std::endl; } \ No newline at end of file diff --git a/game/zworld/src/zworld.cpp b/game/zworld/src/zworld.cpp index c53c13f..f911fd7 100644 --- a/game/zworld/src/zworld.cpp +++ b/game/zworld/src/zworld.cpp @@ -39,5 +39,6 @@ void ZWorldModule::MainLoop() API->BeginFrame(); API->Render(); API->EndFrame(); + FramePool()->reset(); } } diff --git a/xmake.lua b/xmake.lua index 2729b22..02cbfc5 100644 --- a/xmake.lua +++ b/xmake.lua @@ -6,6 +6,8 @@ set_languages("cxx20") set_project("zengine") set_toolchains("clang") set_runtimes("MD","c++_shared") +add_cxflags("-stdlib=libc++") +add_ldflags("-stdlib=libc++") includes("engine") includes("game/*/xmake.lua") --xmake project -k vsxmake2022 -a x64