diff --git a/engine/modules/engine/render/impl/editor_system_impl.inl b/engine/modules/engine/render/impl/editor_system_impl.inl new file mode 100644 index 0000000..1f35e1b --- /dev/null +++ b/engine/modules/engine/render/impl/editor_system_impl.inl @@ -0,0 +1,14 @@ +#include "render/editor_system.h" +namespace api { + SINGLETON_DEFINE(EditorSystem) + EditorSystem::EditorSystem() + { + SINGLETON_PTR(); + } + ImTextureID EditorSystem::AddTexture(FrameGraph& graph, TextureDesc& desc, TextureSampler key) + { + ImageViewPtr imageview = graph.ResolveTextureView(desc); + SamplerPtr sampler = graph.ResolveTextureSampler(key); + return AddTexture(imageview, sampler, desc.state); + } +} \ No newline at end of file diff --git a/engine/modules/engine/render/impl/renderapi_impl.inl b/engine/modules/engine/render/impl/renderapi_impl.inl index ed80342..ee83533 100644 --- a/engine/modules/engine/render/impl/renderapi_impl.inl +++ b/engine/modules/engine/render/impl/renderapi_impl.inl @@ -1,15 +1,5 @@ #include "render/renderapi.h" #include "render/module.h" -#ifdef WITH_EDITOR -#include "render/editor_system.h" -namespace api { - SINGLETON_DEFINE(EditorSystem) - EditorSystem::EditorSystem() - { - SINGLETON_PTR(); - } -} -#endif namespace api { SINGLETON_DEFINE(RenderAPI) IMPLEMENT_STATIC_MODULE(RENDER_API, RenderModule, render); diff --git a/engine/modules/engine/render/include/render/editor_system.h b/engine/modules/engine/render/include/render/editor_system.h index 7b84ecf..8b149df 100644 --- a/engine/modules/engine/render/include/render/editor_system.h +++ b/engine/modules/engine/render/include/render/editor_system.h @@ -4,8 +4,14 @@ #include "module/module_manager.h" #include namespace api { - class RenderEditorContext { - + class EditorSystem; + struct RenderEditorContext { + EditorSystem* editor; + uint32_t frame; + uint32_t frameCount; + EditorSystem* operator->() { + return editor; + } }; class EditorPanel { public: @@ -40,7 +46,8 @@ namespace api { mWindows.push_back(ptr); return ptr; } - virtual ImTextureID AddTexture(const TextureDesc& desc) = 0; + ImTextureID AddTexture(FrameGraph& graph, TextureDesc& desc, TextureSampler sampler); + virtual ImTextureID AddTexture(ImageViewPtr imageview, SamplerPtr sampler, ResourceState state) = 0; }; } #endif // WITH_EDITOR \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/graph/frame_graph.h b/engine/modules/engine/render/include/render/graph/frame_graph.h index 80714ff..ec6912b 100644 --- a/engine/modules/engine/render/include/render/graph/frame_graph.h +++ b/engine/modules/engine/render/include/render/graph/frame_graph.h @@ -6,8 +6,9 @@ namespace api { class FrameGraph { public: - TextureDesc mSurface{}; - table mTextureTagMap; + uint32_t mSurfaceID{0}; + table mTextureSamplerPool; + table mTextureTagMap; table mTextureKeyMap; std::vector mTexturePool; table mTextureViewPool; @@ -17,8 +18,9 @@ namespace api { inline static Name NameSurface{ "surface" }; #ifdef WITH_EDITOR inline static Name NameEditorSurface{ "editor_surface" }; - TextureDesc mEditorSurface{}; bool mIsRenderEditorSurface{false}; + uint32_t mEditorSurfaceID{ 0 }; + TextureDesc& GetEditorSurface() { return ResolveTexture(mEditorSurfaceID); } #endif // public: template @@ -26,23 +28,27 @@ namespace api { FrameGraphNodePtr AddRenderPass(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor); RenderPassBuilder CreateRenderPassBuild(); void InitSurface(TextureDesc* surfaces, uint32_t frames); - void Input(const TextureDesc& surfaces) { mSurface = surfaces; }; + void Input(const TextureDesc& surfaces) { mSurfaceID = surfaces.id; }; void Setup(); void Compile(); void Execute(FRenderView& view); void Clear(); void CullGraph(); void FillGraph(); + TextureDesc& GetSurface() { return ResolveTexture(mSurfaceID); } + TextureDesc& GetRenderSurface(); void TransitionState(TextureDesc& desc, ResourceState state); bool ResolveState(TextureDesc& desc, ResourceState& srcstart, ResourceState& dststate); bool ResolveState(AttachmentDesc& desc, ResourceState& srcstart, ResourceState& dststate); bool ResolveState(BufferDesc& desc, ResourceState& srcstart, ResourceState& dststate); - TextureDesc& ResolveTexture(TextureDesc& desc); + TextureDesc& ResolveTexture(uint32_t id); TextureDesc ResourceTexture(Name name, int num); ImageViewPtr ResolveTextureView(TextureDesc& desc); ImageViewPtr ResolveTextureView(TextureViewKey key); + void* ResolveTextureSampler(TextureSampler sampler); void ResourceTexture(TextureDesc& desc); void SetResourceTexture(TextureDesc texture, Name name, int num = 0); + uint32_t GetTextureID(Name name, int num); public: void ExecutePresentPass(FRenderView& view); void ExecuteRenderPass(RenderPassNode* node, FRenderView& view); diff --git a/engine/modules/engine/render/include/render/graph/frame_graph_builder.inl b/engine/modules/engine/render/include/render/graph/frame_graph_builder.inl index 629943a..979961d 100644 --- a/engine/modules/engine/render/include/render/graph/frame_graph_builder.inl +++ b/engine/modules/engine/render/include/render/graph/frame_graph_builder.inl @@ -11,6 +11,8 @@ namespace api { : graph(*graph) , node(node) {}; RenderPassBuilder& Name(pmr::Name name); RenderPassBuilder& Type(RenderPassNodeType type,RenderPassNodeFlag flag = RenderPassNodeFlag::None); + RenderPassBuilder& Read(TextureDesc desc, ResourceState state, pmr::Name name = {}); RenderPassBuilder& Write(AttachmentDesc desc, ResourceState state, pmr::Name name = {}); + RenderPassBuilder& Dependency(RenderPassNode* rely) { node->dependencies.push_back(rely); return *this;} }; } \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/graph/type.h b/engine/modules/engine/render/include/render/graph/type.h index 93a0633..a64c3b8 100644 --- a/engine/modules/engine/render/include/render/graph/type.h +++ b/engine/modules/engine/render/include/render/graph/type.h @@ -40,9 +40,8 @@ namespace api { using Resource = std::variant; Name name; Resource res; - RenderPassNode* node; FrameResource() noexcept = default; - FrameResource(Name name,const Resource& res, RenderPassNode* node) : name(name), res(res), node(node){}; + FrameResource(Name name,const Resource& res) : name(name), res(res){}; template T& CastTo() { return std::get(res); @@ -56,8 +55,8 @@ namespace api { bool IsBuffer() const { return std::holds_alternative(res); } - static FrameResource* Make(Name name, const Resource& res, RenderPassNode* node) { - return new(FramePool()) FrameResource(name, res, node); + static FrameResource* Make(Name name, const Resource& res) { + return new(FramePool()) FrameResource(name, res); } }; using FrameGraphEdgePtr = FrameResource*; diff --git a/engine/modules/engine/render/include/render/renderapi.h b/engine/modules/engine/render/include/render/renderapi.h index 5a04eb7..53ad743 100644 --- a/engine/modules/engine/render/include/render/renderapi.h +++ b/engine/modules/engine/render/include/render/renderapi.h @@ -35,7 +35,7 @@ namespace api { virtual void CreateBuffer(BufferDesc& desc) = 0; virtual void CreateTexture(TextureDesc& desc) = 0; virtual ImageViewPtr CreateTextureView(TextureViewKey desc) = 0; - + virtual SamplerPtr CreateTextureSampler(TextureSampler sampler) = 0; virtual void BeginFrame() = 0; virtual void EndFrame() = 0; virtual void RenderView(FRenderView& view); diff --git a/engine/modules/engine/render/include/render/type.h b/engine/modules/engine/render/include/render/type.h index ec07d5f..ab70d63 100644 --- a/engine/modules/engine/render/include/render/type.h +++ b/engine/modules/engine/render/include/render/type.h @@ -119,6 +119,91 @@ namespace api { VERTEX = 0x1, FRAGMENT = 0x2, }; + //! Sampler Wrap mode + enum class SamplerWrapMode : uint8_t { + CLAMP_TO_EDGE, //!< clamp-to-edge. The edge of the texture extends to infinity. + REPEAT, //!< repeat. The texture infinitely repeats in the wrap direction. + MIRRORED_REPEAT, //!< mirrored-repeat. The texture infinitely repeats and mirrors in the wrap direction. + }; + + //! Sampler minification filter + enum class SamplerMinFilter : uint8_t { + // don't change the enums values + NEAREST = 0, //!< No filtering. Nearest neighbor is used. + LINEAR = 1, //!< Box filtering. Weighted average of 4 neighbors is used. + NEAREST_MIPMAP_NEAREST = 2, //!< Mip-mapping is activated. But no filtering occurs. + LINEAR_MIPMAP_NEAREST = 3, //!< Box filtering within a mip-map level. + NEAREST_MIPMAP_LINEAR = 4, //!< Mip-map levels are interpolated, but no other filtering occurs. + LINEAR_MIPMAP_LINEAR = 5 //!< Both interpolated Mip-mapping and linear filtering are used. + }; + + //! Sampler magnification filter + enum class SamplerMagFilter : uint8_t { + // don't change the enums values + NEAREST = 0, //!< No filtering. Nearest neighbor is used. + LINEAR = 1, //!< Box filtering. Weighted average of 4 neighbors is used. + }; + + //! Sampler compare mode + enum class SamplerCompareMode : uint8_t { + // don't change the enums values + NONE = 0, + COMPARE_TO_TEXTURE = 1 + }; + + //! 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. + }; + using SamplerPtr = void*; + //! Sampler parameters + struct TextureSampler { // NOLINT + SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST) + SamplerMinFilter filterMin : 3; //!< minification filter (NEAREST) + SamplerWrapMode wrapS : 2; //!< s-coordinate wrap mode (CLAMP_TO_EDGE) + SamplerWrapMode wrapT : 2; //!< t-coordinate wrap mode (CLAMP_TO_EDGE) + + SamplerWrapMode wrapR : 2; //!< r-coordinate wrap mode (CLAMP_TO_EDGE) + uint8_t anisotropyLog2 : 3; //!< anisotropy level (0) + SamplerCompareMode compareMode : 1; //!< sampler compare mode (NONE) + uint8_t padding0 : 2; //!< reserved. must be 0. + + SamplerCompareFunc compareFunc : 3; //!< sampler comparison function (LE) + uint8_t padding1 : 5; //!< reserved. must be 0. + uint8_t padding2 : 8; //!< reserved. must be 0. + struct EqualTo { + bool operator()(TextureSampler lhs, TextureSampler rhs) const noexcept { + auto* pLhs = reinterpret_cast(reinterpret_cast(&lhs)); + auto* pRhs = reinterpret_cast(reinterpret_cast(&rhs)); + return *pLhs == *pRhs; + } + }; + + struct LessThan { + bool operator()(TextureSampler lhs, TextureSampler rhs) const noexcept { + auto* pLhs = reinterpret_cast(reinterpret_cast(&lhs)); + auto* pRhs = reinterpret_cast(reinterpret_cast(&rhs)); + return *pLhs == *pRhs; + } + }; + + private: + friend inline bool operator < (TextureSampler lhs, TextureSampler rhs) noexcept { + return TextureSampler::LessThan{}(lhs, rhs); + } + public: + friend inline bool operator== (TextureSampler lhs, TextureSampler rhs) noexcept { + return TextureSampler::EqualTo{}(lhs, rhs); + } + }; struct MaterialResource { Name name; bool isDirty; @@ -209,6 +294,16 @@ namespace api { uint8_t layerCount; uint8_t baseMipLevel; uint8_t levelCount; + friend inline bool operator==(const TextureViewKey& k1, const TextureViewKey& k2) { + if (k1.image != k2.image) return false; + if (k1.format != k2.format) return false; + if (k1.dimension != k2.dimension) return false; + if (k1.baseArrayLayer != k2.baseArrayLayer) return false; + if (k1.layerCount != k2.layerCount) return false; + if (k1.baseMipLevel != k2.baseMipLevel) return false; + if (k1.levelCount != k2.levelCount) return false; + return true; + } }; struct TextureKey { uint32_t id; @@ -220,6 +315,17 @@ namespace api { TextureDimension dimension; uint8_t mipLevel; uint8_t arraySize; + friend inline bool operator==(const TextureKey& k1, const TextureKey& k2) { + if (k1.format != k2.format) return false; + if (k1.dimension != k2.dimension) return false; + if (k1.width != k2.width) return false; + if (k1.height != k2.height) return false; + if (k1.arraySize != k2.arraySize) return false; + if (k1.mipLevel != k2.mipLevel) return false; + if (k1.sampleCount != k2.sampleCount) return false; + if (k1.depth != k2.depth) return false; + return true; + } }; struct TextureDesc : TextureKey { ImagePtr image; @@ -303,27 +409,6 @@ namespace api { barrier.mTexture = texture; return barrier; } - inline bool operator==(const TextureViewKey& k1, const TextureViewKey& k2) { - if (k1.image != k2.image) return false; - if (k1.format != k2.format) return false; - if (k1.dimension != k2.dimension) return false; - if (k1.baseArrayLayer != k2.baseArrayLayer) return false; - if (k1.layerCount != k2.layerCount) return false; - if (k1.baseMipLevel != k2.baseMipLevel) return false; - if (k1.levelCount != k2.levelCount) return false; - return true; - } - inline bool operator==(const TextureKey& k1, const TextureKey& k2) { - if (k1.format != k2.format) return false; - if (k1.dimension != k2.dimension) return false; - if (k1.width != k2.width) return false; - if (k1.height != k2.height) return false; - if (k1.arraySize != k2.arraySize) return false; - if (k1.mipLevel != k2.mipLevel) return false; - if (k1.sampleCount != k2.sampleCount) return false; - if (k1.depth != k2.depth) return false; - return true; - } } #include "meta/hash.h" namespace std { @@ -335,7 +420,7 @@ namespace std { return meta::MurmurHashFn(key); } }; - template<> + template<> struct hash { size_t operator()(const api::TextureKey& key) const noexcept @@ -343,4 +428,12 @@ namespace std { return meta::MurmurHashFn(key); } }; + template<> + struct hash + { + size_t operator()(const api::TextureSampler& key) const noexcept + { + return std::hash{}(*(int*)&key); + } + }; } \ No newline at end of file diff --git a/engine/modules/engine/render/src/graph/frame_graph.cpp b/engine/modules/engine/render/src/graph/frame_graph.cpp index 7838d8b..78c76e4 100644 --- a/engine/modules/engine/render/src/graph/frame_graph.cpp +++ b/engine/modules/engine/render/src/graph/frame_graph.cpp @@ -17,7 +17,8 @@ namespace api { } void FrameGraph::InitSurface(TextureDesc* surfaces, uint32_t frames) { - mTexturePool.reserve(frames); + mTexturePool.reserve(frames + 1); + mTexturePool.push_back(TextureDesc{}); for (uint32_t i = 0; i < frames;i++) { surfaces[i].id = mTexturePool.size() + 1; mTexturePool.push_back(surfaces[i]); @@ -40,10 +41,8 @@ namespace api { void FrameGraph::CullGraph() { pmr::vector outputNodes{FramePool()}; - std::stack stack; for (auto& node : mNodes) { if (node->IsOutput()) { - stack.push(node.node); outputNodes.push_back(node.node); if ((!mLastOutputNode || node->type > mLastOutputNode->type)) { mLastOutputNode = node.node; @@ -56,23 +55,6 @@ namespace api { } } } - while (!stack.empty()) { - RenderPassNode* node = stack.top(); - stack.pop(); - if (node->isActive) { - continue; - } - node->isActive = true; - for (auto& edge : node->inEdges) { - if (edge->node && !edge->node->isActive) { - stack.push(edge->node); - } - } - } - auto end = std::remove_if(mNodes.begin(), mNodes.end(), [this](FrameGraphNodePtr& node) { - return !node->isActive; - }); - mNodes.erase(end, mNodes.end()); if (outputNodes.size() > 1) { std::sort(outputNodes.begin(), outputNodes.end(), [](RenderPassNode* a, RenderPassNode* b) { if (a->type != b->type) { @@ -84,20 +66,43 @@ namespace api { outputNodes[i]->dependencies.push_back(outputNodes[i - 1]); } } + //todo 需要考虑拓扑排序 + std::stack stack; + stack.push(mLastOutputNode); + while (!stack.empty()) { + RenderPassNode* node = stack.top(); + stack.pop(); + if (node->isActive) { + continue; + } + node->isActive = true; + for (auto& rely : node->dependencies) { + if (!rely->isActive) { + stack.push(rely); + } + } + } + auto end = std::remove_if(mNodes.begin(), mNodes.end(), [this](FrameGraphNodePtr& node) { + return !node->isActive; + }); + mNodes.erase(end, mNodes.end()); } void FrameGraph::FillGraph() { std::pmr::unordered_set seenNodes{FramePool()}; + pmr::vector result{ FramePool() }; for (auto& node : mNodes) { - if (!node->dependencies.empty()) { - seenNodes.insert(node->dependencies[0]); - } - for (auto& edge : node->inEdges) { - RenderPassNode* srcNode = edge->node; - if (srcNode && seenNodes.insert(srcNode).second) { - node->dependencies.push_back(srcNode); + bool isChange = false; + for (auto& rely : node->dependencies) { + bool isInsert = seenNodes.insert(rely).second; + isChange = isChange || !isInsert; + if (isInsert) { + result.push_back(rely); } } + if(isChange) + node->dependencies = result; + result.clear(); seenNodes.clear(); } if (mLastOutputNode) { @@ -105,6 +110,14 @@ namespace api { mLastOutputNode->flag |= RenderPassNodeFlag::LastOutput; } } + TextureDesc& FrameGraph::GetRenderSurface() + { +#ifdef WITH_EDITOR + return ResolveTexture(mIsRenderEditorSurface ? mEditorSurfaceID: mSurfaceID); +#else + return ResolveTexture(mSurfaceID); +#endif // WITH_EDITOR + } void FrameGraph::Execute(FRenderView& view) { for (auto& node : mNodes) { @@ -141,13 +154,8 @@ namespace api { } void FrameGraph::ExecutePresentPass(FRenderView& view) { -#ifdef WITH_EDITOR - TextureDesc& surface = ResolveTexture(mIsRenderEditorSurface ? mEditorSurface : mSurface); -#else - TextureDesc& surface = ResolveTexture(mSurface); -#endif // WITH_EDITOR + TextureDesc& surface = GetRenderSurface(); if (surface.state == ResourceState::PRESENT) { - surface.state = ResourceState::UNDEFINED; return; } TextureBarrier barrier{}; @@ -159,7 +167,6 @@ namespace api { desc.textureBarriersCount = 1; desc.pTextureBarriers = &barrier; view.context->ExecuteSurfaceBarriers(desc); - surface.state = ResourceState::UNDEFINED; } void FrameGraph::ExecuteComputePass(RenderPassNode* node, FRenderView& view) { @@ -204,32 +211,17 @@ namespace api { } void FrameGraph::TransitionState(TextureDesc& desc, ResourceState state) { - TextureDesc& texture = ResolveTexture(desc); + TextureDesc& texture = ResolveTexture(desc.id); desc.state = state; texture.state = state; - if (texture.id == mSurface.id) { - mSurface.state = state; - } -#ifdef WITH_EDITOR - else if (texture.id == mEditorSurface.id) { - mEditorSurface.state = state; - } -#endif // WITH_EDITOR } bool FrameGraph::ResolveState(TextureDesc& desc, ResourceState& srcstart, ResourceState& dststate) { - TextureDesc& texture = ResolveTexture(desc); + TextureDesc& texture = ResolveTexture(desc.id); srcstart = texture.state; dststate = desc.state; texture.state = dststate; - if (texture.id == mSurface.id) { - mSurface.state = dststate; - } -#ifdef WITH_EDITOR - else if (texture.id == mEditorSurface.id) { - mEditorSurface.state = dststate; - } -#endif // WITH_EDITOR + desc.image = texture.image; return srcstart == dststate; } bool FrameGraph::ResolveState(AttachmentDesc& desc, ResourceState& srcstart, ResourceState& dststate) @@ -240,12 +232,12 @@ namespace api { { return true; } - TextureDesc& FrameGraph::ResolveTexture(TextureDesc& desc) + TextureDesc& FrameGraph::ResolveTexture(uint32_t id) { - if (!desc.id || desc.id > mTexturePool.size()) { - return desc; + if (!id || id > mTexturePool.size()) { + return mTexturePool[0];//empty } - TextureDesc& texture = mTexturePool[desc.id - 1]; + TextureDesc& texture = mTexturePool[id - 1]; if (!texture.image) { RenderAPI::Ptr()->CreateTexture(texture); } @@ -254,7 +246,8 @@ namespace api { ImageViewPtr FrameGraph::ResolveTextureView(TextureDesc& desc) { if (!desc.image) { - desc = ResolveTexture(desc); + TextureDesc& texture = ResolveTexture(desc.id); + desc.image = texture.image; } return ResolveTextureView(desc.ToTextureView()); } @@ -268,14 +261,22 @@ namespace api { mTextureViewPool.emplace(key, view); return view; } + void* FrameGraph::ResolveTextureSampler(TextureSampler sampler) + { + auto iter = mTextureSamplerPool.find(sampler); + if (iter != mTextureSamplerPool.end()) { + return iter->second; + } + return RenderAPI::Ptr()->CreateTextureSampler(sampler); + } TextureDesc FrameGraph::ResourceTexture(Name name, int num) { Tag tag(name, num); auto it = mTextureTagMap.find(tag); if (it != mTextureTagMap.end()) { - return it->second; + return ResolveTexture(it->second); } - return TextureDesc{}; + return mTexturePool[0]; } void FrameGraph::ResourceTexture(TextureDesc& desc) { @@ -289,17 +290,28 @@ namespace api { mTexturePool.push_back(desc); } } + uint32_t FrameGraph::GetTextureID(Name name, int num) + { + Tag tag(name, num); + auto it = mTextureTagMap.find(tag); + if (it != mTextureTagMap.end()) { + return it->second; + } + return 0; + } void FrameGraph::SetResourceTexture(TextureDesc desc, Name name, int num) { - if (!desc.id) { + Tag tag(name, num); + auto it = mTextureTagMap.find(tag); + if (it != mTextureTagMap.end()) { + //todo: destroy texture + desc.id = it->second; + mTexturePool[desc.id - 1] = desc; + } + else { desc.id = mTexturePool.size() + 1; mTexturePool.push_back(desc); + mTextureTagMap[tag] = desc.id; } - Tag tag(name, num); - //auto it = mTextureTagMap.find(tag); - //if (it != mTextureTagMap.end()) { - //todo: destroy texture - //} - mTextureTagMap[tag] = desc; } } diff --git a/engine/modules/engine/render/src/graph/frame_graph_builder.cpp b/engine/modules/engine/render/src/graph/frame_graph_builder.cpp index dcb640f..5907792 100644 --- a/engine/modules/engine/render/src/graph/frame_graph_builder.cpp +++ b/engine/modules/engine/render/src/graph/frame_graph_builder.cpp @@ -13,10 +13,18 @@ namespace api { return *this; } + RenderPassBuilder& RenderPassBuilder::Read(TextureDesc desc, ResourceState state, pmr::Name name) + { + desc.state = state; + FrameGraphEdgePtr edge = FrameResource::Make(name, desc); + node->inEdges.push_back(edge); + return *this; + } + RenderPassBuilder& RenderPassBuilder::Write(AttachmentDesc desc, ResourceState state, pmr::Name name) { desc.texture.state = state; - FrameGraphEdgePtr edge = FrameResource::Make(name, desc, node.node); + FrameGraphEdgePtr edge = FrameResource::Make(name, desc); node->outEdges.push_back(edge); return *this; } diff --git a/engine/modules/engine/render/src/pass/demo_pass.cpp b/engine/modules/engine/render/src/pass/demo_pass.cpp index 53484c3..91dba84 100644 --- a/engine/modules/engine/render/src/pass/demo_pass.cpp +++ b/engine/modules/engine/render/src/pass/demo_pass.cpp @@ -11,7 +11,7 @@ namespace api { static RscHandle mesh; void DemoPass::Setup(FrameGraph& graph, RenderPassBuilder& builder) { - AttachmentDesc surface{ graph.mSurface }; + AttachmentDesc surface{ graph.GetSurface()}; builder.Name("MiniPass") .Type(RenderPassNodeType::Scene, RenderPassNodeFlag::Output) .Write(surface, ResourceState::COLOR_ATTACHMENT); @@ -41,7 +41,7 @@ namespace api { auto materialInstance = mesh->GetMaterialInstance(); materialInstance.SetClassResource(Name("uColor"), Vector4{1,0,0,1}); } - auto& surface = graph.mSurface; + auto& surface = graph.GetSurface(); 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/render/vulkan/include/vkn/type.h b/engine/modules/render/vulkan/include/vkn/type.h index fef5844..5c345a4 100644 --- a/engine/modules/render/vulkan/include/vkn/type.h +++ b/engine/modules/render/vulkan/include/vkn/type.h @@ -23,6 +23,8 @@ namespace vkn { using api::ImagePtr; using api::TextureDimension; using api::SampleCount; + using api::TextureSampler; + using api::SamplerPtr; using api::ResourceState; using api::TextureDesc; using api::BufferDesc; @@ -78,6 +80,17 @@ namespace vkn { uint32_t width; uint32_t height; uint32_t layers; + friend inline bool operator==(const FramebufferKey& k1, const FramebufferKey& k2) { + if (k1.pass != k2.pass) return false; + if (k1.attachmentCount != k2.attachmentCount) return false; + for (int i = 0; i < k1.attachmentCount; i++) { + if (k1.imageViews[i] != k2.imageViews[i]) return false; + } + if (k1.height != k2.height) return false; + if (k1.width != k2.width) return false; + if (k1.layers != k2.layers) return false; + return true; + } }; // Equivalent to VkVertexInputAttributeDescription but half as big. struct VertexInputAttributeDescription { @@ -121,17 +134,6 @@ namespace vkn { uint32_t descCount = 0; bool inUse = false; }; - inline bool operator==(const FramebufferKey& k1, const FramebufferKey& k2) { - if (k1.pass != k2.pass) return false; - if (k1.attachmentCount != k2.attachmentCount) return false; - for (int i = 0; i < k1.attachmentCount; i++) { - if (k1.imageViews[i] != k2.imageViews[i]) return false; - } - if (k1.height != k2.height) return false; - if (k1.width != k2.width) return false; - if (k1.layers != k2.layers) return false; - return true; - } } namespace std { template<> diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_api.h b/engine/modules/render/vulkan/include/vkn/vulkan_api.h index c5bee95..2c2c8bd 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_api.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_api.h @@ -2,6 +2,11 @@ #include "vulkan_context.h" #include "asset/res/guid.h" #include "backend.h" +#ifdef API_DEBUG + #define gLogSemaphore(...) //zlog::info(__VA_ARGS__) +#else + #define gLogSemaphore(...) +#endif namespace vkn { class VulkanWindow; using api::Guid; @@ -34,7 +39,7 @@ namespace vkn { void CreateBuffer(BufferDesc& desc) override; void CreateTexture(TextureDesc& desc)override; ImageViewPtr CreateTextureView(TextureViewKey desc)override; - + SamplerPtr CreateTextureSampler(TextureSampler sampler) override; void BeginFrame()override; void EndFrame()override; void BeginRenderPass(RenderPassNode* node, FnEnterRenderPass callback) override; 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 b0cc76f..ba940a3 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_api_help.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_api_help.h @@ -26,4 +26,5 @@ namespace vkn { VkDescriptorType vkApiGetDescriptorType(ShaderDescriptorType type); VkShaderStageFlags vkApiGetShaderStageFlags(ShaderStage stage); VkBufferUsageFlagBits vkApiGetBufferUsage(BufferUsage usage); + VkSamplerCreateInfo vkApiGetSamplerCreateInfo(TextureSampler sampler); } \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_imgui_editor.h b/engine/modules/render/vulkan/include/vkn/vulkan_imgui_editor.h index 3e71836..0eb38be 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_imgui_editor.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_imgui_editor.h @@ -1,8 +1,8 @@ #pragma once #include "render/editor_system.h" #include "render/graph/frame_graph.h" +#include "vkn/vulkan_api.h" namespace vkn { - using api::TextureDesc; using api::FrameGraph; using api::RenderPassContext; using api::RenderPassBuilder; @@ -12,7 +12,7 @@ namespace vkn { void Initialize() override; void Finalize() override; - ImTextureID AddTexture(const TextureDesc& desc) override; + ImTextureID AddTexture(ImageViewPtr imageview, SamplerPtr sampler, ResourceState state) override; void Render(FrameGraph& graph, RenderEditorContext& ctx); void OnBeginRenderFrame(FrameGraph& graph, uint32_t frame); diff --git a/engine/modules/render/vulkan/src/vulkan_api.cpp b/engine/modules/render/vulkan/src/vulkan_api.cpp index 232c3f5..b095d29 100644 --- a/engine/modules/render/vulkan/src/vulkan_api.cpp +++ b/engine/modules/render/vulkan/src/vulkan_api.cpp @@ -325,6 +325,13 @@ namespace vkn { vkCreateImageView(backend.GetDevice().Ptr(), &createInfo, nullptr, &imageView); return (ImageViewPtr)imageView; } + SamplerPtr VulkanAPI::CreateTextureSampler(TextureSampler key) + { + VkSamplerCreateInfo samplerInfo = vkApiGetSamplerCreateInfo(key); + VkSampler sampler; + vkCreateSampler(backend.GetDevice().Ptr(), &samplerInfo, nullptr, &sampler); + return sampler; + } void VulkanAPI::BeginFrame() { VulkanContext& ctx = *(VulkanContext*)&context; @@ -435,13 +442,13 @@ namespace vkn { if (node->IsFirstInput()) { waitDstStageMasks[semaphoreCount] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; waitSemaphores[semaphoreCount++] = ctx.surfaceSemaphore; - //zlog::info("-----wait {:#x}", (uintptr_t)ctx.surfaceSemaphore); + gLogSemaphore("-----wait {:#x}", (uintptr_t)ctx.surfaceSemaphore); } for (auto& it : node->dependencies) { RenderPassInfo* inputInfo = GetRenderPassInfo(it->name ,it->hash); waitDstStageMasks[semaphoreCount] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; waitSemaphores[semaphoreCount++] = inputInfo->semaphores[context.frame]; - //zlog::info("-----wait {:#x}", (uintptr_t)inputInfo->semaphores[context.frame]); + gLogSemaphore("-----wait {:#x}", (uintptr_t)inputInfo->semaphores[context.frame]); } VkSubmitInfo submitInfo{}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; @@ -455,11 +462,12 @@ namespace vkn { VkFence fence = nullptr; if (node->IsLastOutput()) { ctx.graphSemaphore = passInfo->semaphores[context.frame]; - if (graph.mSurface.state == ResourceState::PRESENT) { + TextureDesc& surface = graph.GetRenderSurface(); + if (surface.state == ResourceState::PRESENT) { fence = ctx.surfaceFence; } } - //zlog::info("+++++sign {:#x}", (uintptr_t)passInfo->semaphores[context.frame]); + gLogSemaphore("+++++sign {:#x}", (uintptr_t)passInfo->semaphores[context.frame]); vkQueueSubmit(Backend::RenderWorker->GetQueue().Ptr(), 1, &submitInfo, fence); } RenderPassInfo* VulkanAPI::GetRenderPassInfo(Name name, size_t hash) { diff --git a/engine/modules/render/vulkan/src/vulkan_api_help.cpp b/engine/modules/render/vulkan/src/vulkan_api_help.cpp index c2cdd10..4b1e2be 100644 --- a/engine/modules/render/vulkan/src/vulkan_api_help.cpp +++ b/engine/modules/render/vulkan/src/vulkan_api_help.cpp @@ -184,8 +184,10 @@ namespace vkn { VkImageUsageFlags usageFlags = 0; if (any(usage & TextureUsage::COLOR_ATTACHMENT)) usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - else if (any(usage & TextureUsage::DEPTH_ATTACHMENT)) + if (any(usage & TextureUsage::DEPTH_ATTACHMENT)) usageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + if(any(usage & TextureUsage::SAMPLEABLE)) + usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT; return usageFlags; } VkImageViewType vkApiGetImageViewType(TextureDimension dimension, uint32_t arraySize) @@ -267,4 +269,115 @@ namespace vkn { } return {}; } + using api::SamplerWrapMode; + using api::SamplerMinFilter; + using api::SamplerMagFilter; + using api::SamplerCompareMode; + using api::SamplerCompareFunc; + constexpr inline VkSamplerAddressMode getWrapMode(SamplerWrapMode mode) noexcept { + switch (mode) { + case SamplerWrapMode::REPEAT: + return VK_SAMPLER_ADDRESS_MODE_REPEAT; + case SamplerWrapMode::CLAMP_TO_EDGE: + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + case SamplerWrapMode::MIRRORED_REPEAT: + return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + } + } + + constexpr inline VkFilter getFilter(SamplerMinFilter filter) noexcept { + switch (filter) { + case SamplerMinFilter::NEAREST: + return VK_FILTER_NEAREST; + case SamplerMinFilter::LINEAR: + return VK_FILTER_LINEAR; + case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: + return VK_FILTER_NEAREST; + case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: + return VK_FILTER_LINEAR; + case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: + return VK_FILTER_NEAREST; + case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: + return VK_FILTER_LINEAR; + } + } + + constexpr inline VkFilter getFilter(SamplerMagFilter filter) noexcept { + switch (filter) { + case SamplerMagFilter::NEAREST: + return VK_FILTER_NEAREST; + case SamplerMagFilter::LINEAR: + return VK_FILTER_LINEAR; + } + } + + constexpr inline VkSamplerMipmapMode getMipmapMode(SamplerMinFilter filter) noexcept { + switch (filter) { + case SamplerMinFilter::NEAREST: + return VK_SAMPLER_MIPMAP_MODE_NEAREST; + case SamplerMinFilter::LINEAR: + return VK_SAMPLER_MIPMAP_MODE_NEAREST; + case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: + return VK_SAMPLER_MIPMAP_MODE_NEAREST; + case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: + return VK_SAMPLER_MIPMAP_MODE_NEAREST; + case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: + return VK_SAMPLER_MIPMAP_MODE_LINEAR; + case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: + return VK_SAMPLER_MIPMAP_MODE_LINEAR; + } + } + + constexpr inline float getMaxLod(SamplerMinFilter filter) noexcept { + switch (filter) { + case SamplerMinFilter::NEAREST: + case SamplerMinFilter::LINEAR: + // The Vulkan spec recommends a max LOD of 0.25 to "disable" mipmapping. + // See "Mapping of OpenGL to Vulkan filter modes" in the VK Spec. + return 0.25f; + case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: + case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: + case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: + case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: + return VK_LOD_CLAMP_NONE; + } + } + + constexpr inline VkBool32 getCompareEnable(SamplerCompareMode mode) noexcept { + return mode == SamplerCompareMode::NONE ? VK_FALSE : VK_TRUE; + } + VkCompareOp getCompareOp(SamplerCompareFunc func) { + using Compare = SamplerCompareFunc; + switch (func) { + case Compare::LE: return VK_COMPARE_OP_LESS_OR_EQUAL; + case Compare::GE: return VK_COMPARE_OP_GREATER_OR_EQUAL; + case Compare::L: return VK_COMPARE_OP_LESS; + case Compare::G: return VK_COMPARE_OP_GREATER; + case Compare::E: return VK_COMPARE_OP_EQUAL; + case Compare::NE: return VK_COMPARE_OP_NOT_EQUAL; + case Compare::A: return VK_COMPARE_OP_ALWAYS; + case Compare::N: return VK_COMPARE_OP_NEVER; + } + } + VkSamplerCreateInfo vkApiGetSamplerCreateInfo(TextureSampler sampler) + { + VkSamplerCreateInfo samplerInfo{ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .magFilter = getFilter(sampler.filterMag), + .minFilter = getFilter(sampler.filterMin), + .mipmapMode = getMipmapMode(sampler.filterMin), + .addressModeU = getWrapMode(sampler.wrapS), + .addressModeV = getWrapMode(sampler.wrapT), + .addressModeW = getWrapMode(sampler.wrapR), + .anisotropyEnable = sampler.anisotropyLog2 == 0 ? 0u : 1u, + .maxAnisotropy = (float)(1u << sampler.anisotropyLog2), + .compareEnable = getCompareEnable(sampler.compareMode), + .compareOp = getCompareOp(sampler.compareFunc), + .minLod = 0.0f, + .maxLod = getMaxLod(sampler.filterMin), + .borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK, + .unnormalizedCoordinates = VK_FALSE + }; + return samplerInfo; + } } \ 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 index 11b5982..acefd98 100644 --- a/engine/modules/render/vulkan/src/vulkan_context.cpp +++ b/engine/modules/render/vulkan/src/vulkan_context.cpp @@ -83,8 +83,8 @@ namespace vkn { submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = signalSemaphores; - //zlog::info("-----wait {:#x}", (uintptr_t)waitSemaphores[0]); - //zlog::info("+++++sign {:#x}", (uintptr_t)signalSemaphores[0]); + gLogSemaphore("-----wait {:#x}", (uintptr_t)waitSemaphores[0]); + gLogSemaphore("+++++sign {:#x}", (uintptr_t)signalSemaphores[0]); vkQueueSubmit(queue, 1, &submitInfo, surfaceFence); graphSemaphore = presentSemaphore; } diff --git a/engine/modules/render/vulkan/src/vulkan_imgui_editor.cpp b/engine/modules/render/vulkan/src/vulkan_imgui_editor.cpp index a7154aa..b9e8aff 100644 --- a/engine/modules/render/vulkan/src/vulkan_imgui_editor.cpp +++ b/engine/modules/render/vulkan/src/vulkan_imgui_editor.cpp @@ -1,6 +1,5 @@ #include "vkn/vulkan_imgui_editor.h" #include "vkn/vulkan_window.h" -#include "vkn/vulkan_api.h" #include "vkn/vulkan_api_help.h" #include "vkn/backend.h" #include "vkn/wrapper/device.h" @@ -110,8 +109,8 @@ namespace vkn { //gEngineConfig.IsRenderEditorSurface = true; if (gEngineConfig.IsRenderEditorSurface) { TextureDesc desc{}; - desc.width = 200; - desc.height = 200; + desc.width = 512; + desc.height = 512; desc.format = TinyImageFormat_FromVkFormat((TinyImageFormat_VkFormat)VK_FORMAT_B8G8R8A8_SRGB); desc.state = ResourceState::UNDEFINED; desc.sampleCount = SampleCount::SAMPLE_COUNT_1; @@ -119,7 +118,7 @@ namespace vkn { desc.mipLevel = 1; desc.depth = 1; desc.dimension = TextureDimension::TEX_2D; - desc.usage = TextureUsage::COLOR_ATTACHMENT; + desc.usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE; for (uint32_t i = 0; i < API->context.frameCount; i++) { API->graph.SetResourceTexture(desc, FrameGraph::NameEditorSurface, i); } @@ -130,12 +129,10 @@ namespace vkn { { } - ImTextureID VulkanImguiEditor::AddTexture(const TextureDesc& desc) + ImTextureID VulkanImguiEditor::AddTexture(ImageViewPtr imageview, SamplerPtr sampler, ResourceState state) { - // 2. 通过 ImGui_ImplVulkan_AddTexture 连接 Vulkan 纹理和 ImGui - //ImTextureID textureID = (ImTextureID)(intptr_t)textureImageView; - //ImGui_ImplVulkan_AddTexture(textureSampler, textureImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - return ImTextureID{}; + VkDescriptorSet descriptorSet = ImGui_ImplVulkan_AddTexture((VkSampler)sampler, (VkImageView)imageview, vkApiGetImageLayout(state)); + return reinterpret_cast(descriptorSet); } void VulkanImguiEditor::Render(FrameGraph& graph, RenderEditorContext& ctx) { @@ -148,28 +145,31 @@ namespace vkn { { graph.mIsRenderEditorSurface = gEngineConfig.IsRenderEditorSurface; if (gEngineConfig.IsRenderEditorSurface) { - graph.mEditorSurface = graph.mSurface; - graph.mSurface = graph.ResourceTexture(FrameGraph::NameEditorSurface, frame); + graph.mEditorSurfaceID = graph.mSurfaceID; + graph.mSurfaceID = graph.GetTextureID(FrameGraph::NameEditorSurface, frame); } graph.AddRenderPass(); } void VulkanImguiEditor::Setup(FrameGraph& graph, RenderPassBuilder& builder) { - AttachmentDesc surface{ gEngineConfig.IsRenderEditorSurface ? graph.mEditorSurface : graph.mSurface }; + AttachmentDesc surface{ graph.GetRenderSurface() }; builder.Name(ImguiPassName) .Type(RenderPassNodeType::Imgui, RenderPassNodeFlag::Output) .Write(surface, ResourceState::COLOR_ATTACHMENT); + if (gEngineConfig.IsRenderEditorSurface) { + builder.Read(graph.GetSurface(), ResourceState::READ_ONLY); + } } void VulkanImguiEditor::Execute(FrameGraph& graph, RenderPassContext& context) { - TextureDesc& surface = graph.mEditorSurface.image ? graph.mEditorSurface : graph.mSurface; - graph.TransitionState(surface, ResourceState::PRESENT); + graph.GetRenderSurface().state = ResourceState::PRESENT; ImGui_ImplVulkan_NewFrame(); ImGui_ImplSDL2_NewFrame(); ImGui::NewFrame(); - RenderEditorContext editorContext{}; - VulkanImguiEditor::Ptr()->Render(graph, editorContext); + VulkanImguiEditor* editor = VulkanImguiEditor::Ptr(); + RenderEditorContext editorContext{.editor = editor, .frame = context->frame, .frameCount = context->frameCount }; + editor->Render(graph, editorContext); ImGui::Render(); VulkanContext& ctx = *(VulkanContext*)context.parent; diff --git a/engine/modules/render/vulkan/src/vulkan_window.cpp b/engine/modules/render/vulkan/src/vulkan_window.cpp index 9a1c17e..9bcbbf2 100644 --- a/engine/modules/render/vulkan/src/vulkan_window.cpp +++ b/engine/modules/render/vulkan/src/vulkan_window.cpp @@ -103,11 +103,12 @@ namespace vkn { vkAcquireNextImageKHR(mDevice.Ptr(), mPtr, UINT64_MAX, surfaceSemaphore, VK_NULL_HANDLE, &ctx.presentFrame); vkResetFences(mDevice.Ptr(), 1, &surfaceFence); ctx.surface = mSurfaces[ctx.presentFrame]; - //zlog::info("aquire------------:: {:#x}", (uintptr_t)surfaceSemaphore); + ctx.graphSemaphore = nullptr; + gLogSemaphore("aquire------------:: {:#x}", (uintptr_t)surfaceSemaphore); } void VulkanSwapchain::Present(VulkanContext& ctx) { - //zlog::info("present+++++++++++:: {:#x}", (uintptr_t)ctx.presentSemaphore); + gLogSemaphore("present+++++++++++:: {:#x}", (uintptr_t)ctx.presentSemaphore); VkPresentInfoKHR presentInfo = {}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.pWaitSemaphores = &ctx.graphSemaphore; diff --git a/engine/src/editor/panel/asset_preview_panel.cpp b/engine/src/editor/panel/asset_preview_panel.cpp index ae9ff4c..16f26f4 100644 --- a/engine/src/editor/panel/asset_preview_panel.cpp +++ b/engine/src/editor/panel/asset_preview_panel.cpp @@ -2,16 +2,19 @@ #include "data/global.h" #include namespace api { + TextureSampler sampler; + ImTextureID TextureIDList[10] = {}; void AssetPreviewPanel::DrawPanel(FrameGraph& graph, RenderEditorContext& context) { static float my_float = 0.5f; ImGui::Text("This is some useful text."); ImGui::SliderFloat("float", &my_float, 0.0f, 1.0f); if (gEngineConfig.IsRenderEditorSurface) { - TextureDesc& surface = graph.mSurface; - // 2. 通过 ImGui_ImplVulkan_AddTexture 连接 Vulkan 纹理和 ImGui - //ImTextureID textureID = (ImTextureID)(intptr_t)graph.ResolveTextureView(surface); - // 3. 在 ImGui 窗口中渲染 Vulkan 纹理 - //ImGui::Image(textureID, ImVec2(surface.width, surface.height)); + TextureDesc surface = graph.GetSurface(); + if (!TextureIDList[context.frame]) { + TextureIDList[context.frame] = context->AddTexture(graph, surface, sampler); + } + // 每帧渲染时都可以通过 ImTextureID 使用 + ImGui::Image(TextureIDList[context.frame], ImVec2(surface.width, surface.height)); } } } \ No newline at end of file diff --git a/engine/src/engine/plugin.cpp b/engine/src/engine/plugin.cpp index 8e5127e..eb5f06e 100644 --- a/engine/src/engine/plugin.cpp +++ b/engine/src/engine/plugin.cpp @@ -21,6 +21,9 @@ #define RENDER_API_VAL 1 #include "renderapi_impl.inl" #include "window_impl.inl" +#ifdef WITH_EDITOR + #include "editor_system_impl.inl" +#endif #endif // !RENDER_API_VAL #ifndef APP_API_VAL