diff --git a/engine/modules/engine/render/include/render/asset/desc/attachment_desc.h b/engine/modules/engine/render/include/render/asset/desc/attachment_desc.h deleted file mode 100644 index ffa8aae..0000000 --- a/engine/modules/engine/render/include/render/asset/desc/attachment_desc.h +++ /dev/null @@ -1,48 +0,0 @@ -#include "asset/res/resource_handle.h" -#include "math/vector2.h" -#include "render_enum.h" -namespace api { - /* - class Texture; - struct Attachment - { - re::LoadOp load_op{}; - re::StoreOp store_op{}; - re::LoadOp stencil_load_op{}; - re::StoreOp stencil_store_op{}; - bool own_buffer = false; - RscHandle buffer; - RscHandle operator*()const { return buffer; } - operator RscHandle()const { return buffer; } - const RscHandle* operator->()const { return &buffer; } - Attachment() = default; - Attachment(const Attachment&) = delete; - Attachment(Attachment&& rhs) : own_buffer{ rhs.own_buffer }, buffer{ rhs.buffer } - { - rhs.own_buffer = false; - rhs.buffer = {}; - } - Attachment& operator=(const Attachment&) = delete; - Attachment& operator=(Attachment&&) = default; - virtual ~Attachment(); - }; - struct TextureDesc - { - string name; - Vector2 size; - re::Format format; - static TextureDesc Make() { - return {}; - } - }; - struct AttachmentDesc - { - re::LoadOp load_op; - re::StoreOp store_op; - re::LoadOp stencil_load_op; - re::StoreOp stencil_store_op; - static AttachmentDesc Make() { - return {}; - } - };*/ -} \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/asset/desc/render_enum.h b/engine/modules/engine/render/include/render/asset/desc/render_enum.h deleted file mode 100644 index 3039779..0000000 --- a/engine/modules/engine/render/include/render/asset/desc/render_enum.h +++ /dev/null @@ -1,25 +0,0 @@ -#include -namespace api::re { - enum class StoreOp : uint8_t - { - eDontCare, - eStore - }; - enum class LoadOp : uint8_t - { - eDontCare, - eClear, - eLoad - }; - enum AttachmentType : uint8_t - { - eColor, - eDepth, - eStencil, - eDepth3D, - eSizeAT - }; - enum class Format : uint16_t { - - }; -} \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/asset/texture.h b/engine/modules/engine/render/include/render/asset/texture.h index 5f7e3d1..bbe19b4 100644 --- a/engine/modules/engine/render/include/render/asset/texture.h +++ b/engine/modules/engine/render/include/render/asset/texture.h @@ -1,12 +1,11 @@ #pragma once #include "asset/asset.h" -#include "render/type.h" +#include "render/render_type.h" namespace api { class Texture : public Resource { public: TextureDesc mDesc; - void* mPtr; public: Texture(TextureDesc& desc); }; 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 ec6912b..19cd273 100644 --- a/engine/modules/engine/render/include/render/graph/frame_graph.h +++ b/engine/modules/engine/render/include/render/graph/frame_graph.h @@ -1,18 +1,23 @@ #pragma once -#include "type.h" +#include "frame_graph_node.h" namespace api { struct FRenderView; using pmr::Tag; class FrameGraph { public: - uint32_t mSurfaceID{0}; - table mTextureSamplerPool; - table mTextureTagMap; - table mTextureKeyMap; - std::vector mTexturePool; - table mTextureViewPool; - pmr::vector mNodes{FramePool()}; + struct TextureID{ + uint32_t id; + uint32_t tick; + }; + uint32_t mTickStamp{1}; + uint32_t mSurfaceID{0}; + table mTextureSamplerPool; + table mTextureTagMap; + table> mTextureKeyMap;//一张图不够用了 + std::vector mTexturePool; + table mTextureViewPool; + pmr::vector mNodes{FramePool()}; RenderPassNode* mFirstInputNode{ nullptr }; RenderPassNode* mLastOutputNode{ nullptr }; inline static Name NameSurface{ "surface" }; @@ -39,16 +44,16 @@ namespace api { 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(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); + void AcquireTexture(TextureDesc& desc); + void RealeaseTexture(TextureDesc& desc); public: void ExecutePresentPass(FRenderView& view); void ExecuteRenderPass(RenderPassNode* node, FRenderView& view); @@ -57,5 +62,4 @@ namespace api { static void ExecuteResourceBarriers(RenderPassNode* node, RenderPassType type); }; -} -#include "frame_graph_builder.inl" \ No newline at end of file +} \ No newline at end of file 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 deleted file mode 100644 index 979961d..0000000 --- a/engine/modules/engine/render/include/render/graph/frame_graph_builder.inl +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -namespace api { - struct RenderPassBuilder { - FrameGraph& graph; - FrameGraphNodePtr node; - FrameResource* resource{nullptr}; - public: - RenderPassBuilder(FrameGraph* graph) noexcept - : graph(*graph), node() {}; - RenderPassBuilder(FrameGraph* graph, FrameGraphNodePtr& node) noexcept - : 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/frame_graph_node.h similarity index 76% rename from engine/modules/engine/render/include/render/graph/type.h rename to engine/modules/engine/render/include/render/graph/frame_graph_node.h index a64c3b8..6c21091 100644 --- a/engine/modules/engine/render/include/render/graph/type.h +++ b/engine/modules/engine/render/include/render/graph/frame_graph_node.h @@ -1,9 +1,8 @@ #pragma once -#include "asset/asset.h" -#include "render/type.h" -#include -namespace api { - class FrameGraph; +#include "meta/enum.h" +#include "render/render_type.h" +namespace api{ + class FrameGraph; class RenderPassBuilder; struct RenderPassNode; struct RenderContext; @@ -37,7 +36,7 @@ namespace api { } }; struct FrameResource { - using Resource = std::variant; + using Resource = std::variant; Name name; Resource res; FrameResource() noexcept = default; @@ -46,9 +45,6 @@ namespace api { T& CastTo() { return std::get(res); } - bool IsAttachment() const { - return std::holds_alternative(res); - } bool IsTexture() const{ return std::holds_alternative(res); } @@ -60,18 +56,6 @@ namespace api { } }; using FrameGraphEdgePtr = FrameResource*; - enum class RenderPassNodeType : uint8_t { - None, - Scene, - Imgui, - }; - enum class RenderPassNodeFlag : uint8_t - { - None = 0, - Output = 0x01, - FirstInput = 0x02, - LastOutput = 0x04, - }; using RenderPassEdgeIterFn = std::function; struct RenderPassNode { Name name; @@ -79,6 +63,7 @@ namespace api { RenderPassNodeType type{0}; RenderPassNodeFlag flag{0}; bool isActive{ false }; + RenderPassParams params{}; RenderPassSetupFunction setup; RenderPassNodeExecuteFn executor; pmr::vector dependencies{ FramePool() }; @@ -113,4 +98,20 @@ namespace api { { return node->hash; } + struct RenderPassBuilder { + FrameGraph& graph; + FrameGraphNodePtr node; + FrameResource* resource{ nullptr }; + public: + RenderPassBuilder(FrameGraph* graph) noexcept + : graph(*graph), node() {}; + RenderPassBuilder(FrameGraph* graph, FrameGraphNodePtr& node) noexcept + : 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(TextureDesc desc, ResourceState state, pmr::Name name = {}); + RenderPassBuilder& Dependency(RenderPassNode* rely) { node->dependencies.push_back(rely); return *this; } + RenderPassBuilder& Attachment(AttachmentFlag flag); + }; } \ No newline at end of file diff --git a/engine/modules/engine/render/include/render/render_context.h b/engine/modules/engine/render/include/render/render_context.h index 5b281fd..3d972db 100644 --- a/engine/modules/engine/render/include/render/render_context.h +++ b/engine/modules/engine/render/include/render/render_context.h @@ -1,5 +1,6 @@ #pragma once #include "type.h" +#include "render_type.h" namespace api { struct RenderContext; struct FRenderView { diff --git a/engine/modules/engine/render/include/render/render_type.h b/engine/modules/engine/render/include/render/render_type.h new file mode 100644 index 0000000..4e369cd --- /dev/null +++ b/engine/modules/engine/render/include/render/render_type.h @@ -0,0 +1,365 @@ +#pragma once +#include "tinyimageformat/tinyimageformat_base.h" +#include "math/vector2.h" +#include "math/vector4.h" +#include "asset/asset.h" +#include +namespace api { + enum class RenderPassType : uint8_t { + Render, + Present, + Compute, + Copy + }; + enum class AttachmentFlag : uint8_t { + None = 0, + Clear = 0x01, + DiscardStart = 0x02, + DiscardEnd = 0x04, + DepthStencil = 0x08, + MainPass = 0x10, + Subpass = 0x20, + Sample = 0x40, + }; + enum class RenderPassNodeType : uint8_t { + None, + Scene, + Imgui, + }; + enum class RenderPassNodeFlag : uint8_t + { + None = 0, + Output = 0x01, + FirstInput = 0x02, + LastOutput = 0x04, + }; + enum class BufferUsage : uint8_t { + STATIC = 0x01, //!< content modified once, used many times + DYNAMIC = 0x02, //!< content modified frequently, used many times + VERTEX = 0x04, + UNIFORM = 0x08, + SHADER_STORAGE = 0x10 + }; + enum class ResourceMemoryUsage : uint8_t + { + /// No intended memory usage specified. + UNKNOWN = 0, + /// Memory will be used on device only, no need to be mapped on host. + GPU_ONLY = 1, + /// Memory will be mapped on host. Could be used for transfer to device. + CPU_ONLY = 2, + /// Memory will be used for frequent (dynamic) updates from host and reads on device. + CPU_TO_GPU = 3, + /// Memory will be used for writing on device and readback on host. + GPU_TO_CPU = 4, + COUNT, + }; + enum SampleCount : uint8_t + { + SAMPLE_COUNT_1 = 1, + SAMPLE_COUNT_2 = 2, + SAMPLE_COUNT_4 = 4, + SAMPLE_COUNT_8 = 8, + SAMPLE_COUNT_16 = 16, + SAMPLE_COUNT_COUNT = 5, + }; + enum class ResourceState : uint8_t + { + // The initial layout after the creation of the VkImage. We use this to denote the state before + // any transition. + UNDEFINED, + // Fragment/vertex shader accessible layout for reading and writing. + READ_WRITE, + // Fragment/vertex shader accessible layout for reading only. + READ_ONLY, + // For the source of a copy operation. + TRANSFER_SRC, + // For the destination of a copy operation. + TRANSFER_DST, + // For using a depth texture as an attachment. + DEPTH_ATTACHMENT, + // For using a depth texture both as an attachment and as a sampler. + DEPTH_SAMPLER, + // For swapchain images that will be presented. + PRESENT, + // For color attachments, but also used when the image is a sampler. + // TODO: explore separate layout policies for attachment+sampling and just attachment. + COLOR_ATTACHMENT, + }; + enum class TextureUsage :uint16_t { + NONE = 0x0000, + COLOR_ATTACHMENT = 0x0001, //!< Texture can be used as a color attachment + DEPTH_ATTACHMENT = 0x0002, //!< Texture can be used as a depth attachment + STENCIL_ATTACHMENT = 0x0004, //!< Texture can be used as a stencil attachment + UPLOADABLE = 0x0008, //!< Data can be uploaded into this texture (default) + SAMPLEABLE = 0x0010, //!< Texture can be sampled (default) + SUBPASS_INPUT = 0x0020, //!< Texture can be used as a subpass input + BLIT_SRC = 0x0040, //!< Texture can be used the source of a blit() + BLIT_DST = 0x0080, //!< Texture can be used the destination of a blit() + PROTECTED = 0x0100, //!< Texture can be used for protected content + DEFAULT = UPLOADABLE | SAMPLEABLE //!< Default texture usage + }; + enum class TextureDimension : uint8_t + { + TEX_NULL = 0, + TEX_1D = 0x01, + TEX_2D = 0x02, + TEX_3D = 0x04, + TEX_CUBE = 0x08, + }; + //! 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); + } + }; + using ImagePtr = void*; + using ImageViewPtr = void*; + using BufferPtr = void*; + struct BufferBarrier; + struct TextureBarrier; + struct BufferDesc { + BufferPtr buffer; + void* mappingAddr; + uint32_t size; + BufferUsage usage; + ResourceMemoryUsage memoryUsage; + static BufferDesc Make() { + return {}; + } + BufferBarrier ToBarrier(ResourceState from, ResourceState to)const; + }; + struct TextureViewKey { + ImagePtr image; + TinyImageFormat format; + TextureDimension dimension; + uint8_t baseArrayLayer; + 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; + uint16_t width; + uint16_t height; + uint16_t depth; + TinyImageFormat format; + SampleCount sampleCount; + 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; + void* pData;//api数据 比如 vulkan 包含了内存信息,删除图像时要用到 + ResourceState state; + TextureUsage usage;//这个字段是包含关系,即使不同,也可以指向相同的图像 + //MSAA 多重采样解析纹理 + TextureDesc Resolve(uint32_t id = 0) { + TextureDesc resolve{ *(TextureKey*)this }; + resolve.id = id; + resolve.sampleCount = SampleCount::SAMPLE_COUNT_1; + return resolve; + } + TextureViewKey ToTextureView() const { + TextureViewKey desc{}; + desc.image = image; + desc.format = format; + desc.baseArrayLayer = 0; + desc.baseMipLevel = 0; + desc.layerCount = 1; + desc.levelCount = 1; + desc.dimension = dimension; + return desc; + } + TextureBarrier ToBarrier(ResourceState from, ResourceState to)const; + }; + struct TextureBarrier + { + TextureDesc mTexture; + ResourceState mSrcState; + ResourceState mDstState; + uint8_t mBeginOnly : 1; + uint8_t mEndOnly : 1; + uint8_t mAcquire : 1; + uint8_t mRelease : 1; + uint8_t mQueueType : 5; + /// Specifiy whether following barrier targets particular subresource + uint8_t mSubresourceBarrier : 1; + /// Following values are ignored if mSubresourceBarrier is false + uint8_t mMipLevel : 7; + uint16_t mArrayLayer; + }; + typedef struct BufferBarrier + { + //Buffer* pBuffer; + ResourceState mSrcState; + ResourceState mDstState; + uint8_t mBeginOnly : 1; + uint8_t mEndOnly : 1; + } BufferBarrier; + inline BufferBarrier BufferDesc::ToBarrier(ResourceState from, ResourceState to)const + { + BufferBarrier barrier{}; + barrier.mSrcState = from; + barrier.mDstState = to; + return barrier; + } + inline TextureBarrier TextureDesc::ToBarrier(ResourceState from, ResourceState to)const + { + TextureBarrier barrier{}; + barrier.mSrcState = from; + barrier.mDstState = to; + barrier.mTexture = *this; + return barrier; + } + struct ResourceBarrierDesc { + RenderPassType type; + const BufferBarrier* pBufferBarriers; + uint32_t bufferBarriersCount; + const TextureBarrier* pTextureBarriers; + uint32_t textureBarriersCount; + }; + /** + * Parameters of a render pass. + */ + struct RenderPassParams { + uint8_t passMask; + uint8_t subpassMask; + uint8_t sampleMask; + uint8_t clear; + uint8_t discardStart;//不关心加载内容 + uint8_t discardEnd;//数据存储在访问最快的地方,只能在RenderPass内部用,后面就找不到了(不在附件里) + Vector2 depthRange{ 0.f, 1.f }; //!< depth range for this pass + Vector4 clearColor = { 0.f, 0.f, 0.f, 1.f }; + float clearDepth; + uint32_t clearStencil; + }; +} +#include "meta/hash.h" +namespace std { + template<> + struct hash + { + size_t operator()(const api::TextureViewKey& key) const noexcept + { + return meta::MurmurHashFn(key); + } + }; + template<> + struct hash + { + size_t operator()(const api::TextureKey& key) const noexcept + { + 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/include/render/type.h b/engine/modules/engine/render/include/render/type.h index ab70d63..637278d 100644 --- a/engine/modules/engine/render/include/render/type.h +++ b/engine/modules/engine/render/include/render/type.h @@ -1,116 +1,9 @@ #pragma once -#include "meta/enum.h" #include "refl/pch.h" -#include "tinyimageformat/tinyimageformat_base.h" #include -//#include namespace api { using pmr::Name; - enum class GraphicsAPI : uint8_t - { - OpenGL, - Vulkan, - D3D12 - }; - enum class RenderPassType : uint8_t { - Render, - Present, - Compute, - Copy - }; - enum class BufferUsage : uint8_t { - STATIC = 0x01, //!< content modified once, used many times - DYNAMIC = 0x02, //!< content modified frequently, used many times - VERTEX = 0x04, - UNIFORM = 0x08, - SHADER_STORAGE = 0x10 - }; - enum class ResourceMemoryUsage : uint8_t - { - /// No intended memory usage specified. - UNKNOWN = 0, - /// Memory will be used on device only, no need to be mapped on host. - GPU_ONLY = 1, - /// Memory will be mapped on host. Could be used for transfer to device. - CPU_ONLY = 2, - /// Memory will be used for frequent (dynamic) updates from host and reads on device. - CPU_TO_GPU = 3, - /// Memory will be used for writing on device and readback on host. - GPU_TO_CPU = 4, - COUNT, - }; - enum SampleCount : uint8_t - { - SAMPLE_COUNT_1 = 1, - SAMPLE_COUNT_2 = 2, - SAMPLE_COUNT_4 = 4, - SAMPLE_COUNT_8 = 8, - SAMPLE_COUNT_16 = 16, - SAMPLE_COUNT_COUNT = 5, - }; - enum class TargetBufferFlags : uint32_t { - NONE = 0x0u, //!< No buffer selected. - COLOR0 = 0x00000001u, //!< Color buffer selected. - COLOR1 = 0x00000002u, //!< Color buffer selected. - COLOR2 = 0x00000004u, //!< Color buffer selected. - COLOR3 = 0x00000008u, //!< Color buffer selected. - COLOR4 = 0x00000010u, //!< Color buffer selected. - COLOR5 = 0x00000020u, //!< Color buffer selected. - COLOR6 = 0x00000040u, //!< Color buffer selected. - COLOR7 = 0x00000080u, //!< Color buffer selected. - - COLOR = COLOR0, //!< \deprecated - COLOR_ALL = COLOR0 | COLOR1 | COLOR2 | COLOR3 | COLOR4 | COLOR5 | COLOR6 | COLOR7, - DEPTH = 0x10000000u, //!< Depth buffer selected. - STENCIL = 0x20000000u, //!< Stencil buffer selected. - DEPTH_AND_STENCIL = DEPTH | STENCIL, //!< depth and stencil buffer selected. - ALL = COLOR_ALL | DEPTH | STENCIL //!< Color, depth and stencil buffer selected. - }; - enum class ResourceState : uint8_t - { - // The initial layout after the creation of the VkImage. We use this to denote the state before - // any transition. - UNDEFINED, - // Fragment/vertex shader accessible layout for reading and writing. - READ_WRITE, - // Fragment/vertex shader accessible layout for reading only. - READ_ONLY, - // For the source of a copy operation. - TRANSFER_SRC, - // For the destination of a copy operation. - TRANSFER_DST, - // For using a depth texture as an attachment. - DEPTH_ATTACHMENT, - // For using a depth texture both as an attachment and as a sampler. - DEPTH_SAMPLER, - // For swapchain images that will be presented. - PRESENT, - // For color attachments, but also used when the image is a sampler. - // TODO: explore separate layout policies for attachment+sampling and just attachment. - COLOR_ATTACHMENT, - }; - enum class TextureUsage :uint16_t { - NONE = 0x0000, - COLOR_ATTACHMENT = 0x0001, //!< Texture can be used as a color attachment - DEPTH_ATTACHMENT = 0x0002, //!< Texture can be used as a depth attachment - STENCIL_ATTACHMENT = 0x0004, //!< Texture can be used as a stencil attachment - UPLOADABLE = 0x0008, //!< Data can be uploaded into this texture (default) - SAMPLEABLE = 0x0010, //!< Texture can be sampled (default) - SUBPASS_INPUT = 0x0020, //!< Texture can be used as a subpass input - BLIT_SRC = 0x0040, //!< Texture can be used the source of a blit() - BLIT_DST = 0x0080, //!< Texture can be used the destination of a blit() - PROTECTED = 0x0100, //!< Texture can be used for protected content - DEFAULT = UPLOADABLE | SAMPLEABLE //!< Default texture usage - }; - enum class TextureDimension : uint8_t - { - TEX_NULL = 0, - TEX_1D = 0x01, - TEX_2D = 0x02, - TEX_3D = 0x04, - TEX_CUBE = 0x08, - }; - enum class ShaderDescriptorType : uint8_t{ + enum class ShaderDescriptorType : uint8_t { UNIFORM_BUFFER, SAMPLER, }; @@ -119,91 +12,12 @@ 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); - } - }; + enum class GraphicsAPI : uint8_t + { + OpenGL, + Vulkan, + D3D12 + }; struct MaterialResource { Name name; bool isDirty; @@ -270,170 +84,4 @@ namespace api { ShaderStage stageFlags; }; using ShaderDescriptorSet = pmr::vector; - using ImagePtr = void*; - using ImageViewPtr = void*; - using BufferPtr = void*; - struct BufferBarrier; - struct TextureBarrier; - struct BufferDesc { - BufferPtr buffer; - void* mappingAddr; - uint32_t size; - BufferUsage usage; - ResourceMemoryUsage memoryUsage; - static BufferDesc Make() { - return {}; - } - BufferBarrier ToBarrier(ResourceState from, ResourceState to)const; - }; - struct TextureViewKey { - ImagePtr image; - TinyImageFormat format; - TextureDimension dimension; - uint8_t baseArrayLayer; - 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; - uint16_t width; - uint16_t height; - uint16_t depth; - TinyImageFormat format; - SampleCount sampleCount; - 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; - void* pData;//api数据 比如 vulkan 包含了内存信息,删除图像时要用到 - ResourceState state; - TextureUsage usage;//这个字段是包含关系,即使不同,也可以指向相同的图像 - TextureViewKey ToTextureView() const{ - TextureViewKey desc{}; - desc.image = image; - desc.format = format; - desc.baseArrayLayer = 0; - desc.baseMipLevel = 0; - desc.layerCount = 1; - desc.levelCount = 1; - desc.dimension = dimension; - return desc; - } - TextureBarrier ToBarrier(ResourceState from, ResourceState to)const; - }; - struct AttachmentDesc { - TextureDesc texture; - ImageViewPtr imageView; - AttachmentDesc() :texture(), imageView(nullptr) {}; - AttachmentDesc(const TextureDesc& desc): texture(desc), imageView(nullptr){} - TextureViewKey ToTextureView() const { - return texture.ToTextureView(); - } - TextureBarrier ToBarrier(ResourceState from, ResourceState to)const; - }; - struct TextureBarrier - { - TextureDesc mTexture; - ResourceState mSrcState; - ResourceState mDstState; - uint8_t mBeginOnly : 1; - uint8_t mEndOnly : 1; - uint8_t mAcquire : 1; - uint8_t mRelease : 1; - uint8_t mQueueType : 5; - /// Specifiy whether following barrier targets particular subresource - uint8_t mSubresourceBarrier : 1; - /// Following values are ignored if mSubresourceBarrier is false - uint8_t mMipLevel : 7; - uint16_t mArrayLayer; - }; - typedef struct BufferBarrier - { - //Buffer* pBuffer; - ResourceState mSrcState; - ResourceState mDstState; - uint8_t mBeginOnly : 1; - uint8_t mEndOnly : 1; - } BufferBarrier; - struct ResourceBarrierDesc { - RenderPassType type; - const BufferBarrier* pBufferBarriers; - uint32_t bufferBarriersCount; - const TextureBarrier* pTextureBarriers; - uint32_t textureBarriersCount; - }; - inline BufferBarrier BufferDesc::ToBarrier(ResourceState from, ResourceState to)const - { - BufferBarrier barrier{}; - barrier.mSrcState = from; - barrier.mDstState = to; - return barrier; - } - inline TextureBarrier TextureDesc::ToBarrier(ResourceState from, ResourceState to)const - { - TextureBarrier barrier{}; - barrier.mSrcState = from; - barrier.mDstState = to; - barrier.mTexture = *this; - return barrier; - } - inline TextureBarrier AttachmentDesc::ToBarrier(ResourceState from, ResourceState to)const - { - TextureBarrier barrier{}; - barrier.mSrcState = from; - barrier.mDstState = to; - barrier.mTexture = texture; - return barrier; - } -} -#include "meta/hash.h" -namespace std { - template<> - struct hash - { - size_t operator()(const api::TextureViewKey& key) const noexcept - { - return meta::MurmurHashFn(key); - } - }; - template<> - struct hash - { - size_t operator()(const api::TextureKey& key) const noexcept - { - 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 78c76e4..639f005 100644 --- a/engine/modules/engine/render/src/graph/frame_graph.cpp +++ b/engine/modules/engine/render/src/graph/frame_graph.cpp @@ -142,6 +142,7 @@ namespace api { mNodes.clear(); mFirstInputNode = nullptr; mLastOutputNode = nullptr; + mTickStamp++; } void FrameGraph::ExecuteRenderPass(RenderPassNode* node, FRenderView& view) { @@ -224,10 +225,6 @@ namespace api { desc.image = texture.image; return srcstart == dststate; } - bool FrameGraph::ResolveState(AttachmentDesc& desc, ResourceState& srcstart, ResourceState& dststate) - { - return ResolveState(desc.texture, srcstart, dststate); - } bool FrameGraph::ResolveState(BufferDesc& desc, ResourceState& srcstart, ResourceState& dststate) { return true; @@ -278,18 +275,6 @@ namespace api { } return mTexturePool[0]; } - void FrameGraph::ResourceTexture(TextureDesc& desc) - { - auto it = mTextureKeyMap.find(desc); - if (it != mTextureKeyMap.end()) { - desc.id = it->second; - } - else { - desc.id = mTexturePool.size() + 1; - mTextureKeyMap[desc] = desc.id; - mTexturePool.push_back(desc); - } - } uint32_t FrameGraph::GetTextureID(Name name, int num) { Tag tag(name, num); @@ -299,6 +284,35 @@ namespace api { } return 0; } + void FrameGraph::AcquireTexture(TextureDesc& desc) + { + auto it = mTextureKeyMap.find(desc); + if (it != mTextureKeyMap.end()) { + for (auto& id : it->second) { + if (id.tick != mTickStamp) { + desc.id = id.id; + return; + } + } + } + desc.id = mTexturePool.size() + 1; + TextureID id{ desc.id , mTickStamp }; + mTexturePool.push_back(desc); + mTextureKeyMap[desc].push_back(id); + } + void FrameGraph::RealeaseTexture(TextureDesc& desc) + { + auto it = mTextureKeyMap.find(desc); + if (it != mTextureKeyMap.end()) { + for (auto& id : it->second) { + if (id.id == desc.id) { + id.tick = mTickStamp - 1; + desc.id = 0; + return; + } + } + } + } void FrameGraph::SetResourceTexture(TextureDesc desc, Name name, int num) { Tag tag(name, num); diff --git a/engine/modules/engine/render/src/graph/frame_graph_builder.cpp b/engine/modules/engine/render/src/graph/frame_graph_builder.cpp deleted file mode 100644 index 5907792..0000000 --- a/engine/modules/engine/render/src/graph/frame_graph_builder.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "render/graph/frame_graph.h" -#include "render/pass/render_pass.h" -namespace api { - RenderPassBuilder& RenderPassBuilder::Name(pmr::Name name) - { - node->name = name; - return *this; - } - RenderPassBuilder& RenderPassBuilder::Type(RenderPassNodeType type, RenderPassNodeFlag flag) - { - node->type = type; - node->flag = flag; - 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->outEdges.push_back(edge); - return *this; - } - -} \ No newline at end of file diff --git a/engine/modules/engine/render/src/graph/frame_graph_node.cpp b/engine/modules/engine/render/src/graph/frame_graph_node.cpp new file mode 100644 index 0000000..1f6d52f --- /dev/null +++ b/engine/modules/engine/render/src/graph/frame_graph_node.cpp @@ -0,0 +1,73 @@ +#include "render/graph/frame_graph.h" +#include "render/pass/render_pass.h" +namespace api { + void RenderPassNode::ForeachEdge(RenderPassEdgeIterFn fn) { + for (auto& edge : inEdges) { + fn(edge); + } + for (auto& edge : outEdges) { + fn(edge); + } + } + FrameGraphNodePtr::FrameGraphNodePtr(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor, NodeType type) : type(type) + { + node = new (FramePool()) RenderPassNode(); + node->setup = setup; + node->executor = executor; + } + RenderPassBuilder& RenderPassBuilder::Name(pmr::Name name) + { + node->name = name; + return *this; + } + RenderPassBuilder& RenderPassBuilder::Type(RenderPassNodeType type, RenderPassNodeFlag flag) + { + node->type = type; + node->flag = flag; + 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(TextureDesc desc, ResourceState state, pmr::Name name) + { + desc.state = state; + FrameGraphEdgePtr edge = FrameResource::Make(name, desc); + node->outEdges.push_back(edge); + return *this; + } + + RenderPassBuilder& RenderPassBuilder::Attachment(AttachmentFlag flag) + { + uint32_t mask = node->outEdges.size(); + if (mask && any(flag)) { + mask = 1 << (mask - 1); + if (any(flag & AttachmentFlag::Clear)) { + node->params.clear |= mask; + } + if (any(flag & AttachmentFlag::DiscardStart)) { + node->params.discardStart |= mask; + } + if (any(flag & AttachmentFlag::DiscardEnd)) { + node->params.discardEnd |= mask; + } + if (any(flag & AttachmentFlag::Sample)) { + node->params.sampleMask |= mask; + } + if (any(flag & AttachmentFlag::MainPass)) { + node->params.passMask |= mask; + } + if (any(flag & AttachmentFlag::Subpass)) { + node->params.subpassMask |= mask; + } + } + return *this; + } + +} \ No newline at end of file diff --git a/engine/modules/engine/render/src/graph/type.cpp b/engine/modules/engine/render/src/graph/type.cpp deleted file mode 100644 index ee2ae1a..0000000 --- a/engine/modules/engine/render/src/graph/type.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "render/graph/type.h" -#include "render/renderapi.h" -namespace api { - void RenderPassNode::ForeachEdge(RenderPassEdgeIterFn fn) { - for (auto& edge : inEdges) { - fn(edge); - } - for (auto& edge : outEdges) { - fn(edge); - } - } - FrameGraphNodePtr::FrameGraphNodePtr(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor, NodeType type) : type(type) - { - node = new (FramePool()) RenderPassNode(); - node->setup = setup; - node->executor = executor; - } -} diff --git a/engine/modules/engine/render/src/pass/demo_pass.cpp b/engine/modules/engine/render/src/pass/demo_pass.cpp index 91dba84..97ca325 100644 --- a/engine/modules/engine/render/src/pass/demo_pass.cpp +++ b/engine/modules/engine/render/src/pass/demo_pass.cpp @@ -11,10 +11,10 @@ namespace api { static RscHandle mesh; void DemoPass::Setup(FrameGraph& graph, RenderPassBuilder& builder) { - AttachmentDesc surface{ graph.GetSurface()}; builder.Name("MiniPass") .Type(RenderPassNodeType::Scene, RenderPassNodeFlag::Output) - .Write(surface, ResourceState::COLOR_ATTACHMENT); + .Write(graph.GetSurface(), ResourceState::COLOR_ATTACHMENT) + .Attachment(AttachmentFlag::Clear); } void DemoPass::Execute(FrameGraph& graph, RenderPassContext& ctx) { diff --git a/engine/modules/render/vulkan/include/vkn/type.h b/engine/modules/render/vulkan/include/vkn/type.h index 5c345a4..1383f3a 100644 --- a/engine/modules/render/vulkan/include/vkn/type.h +++ b/engine/modules/render/vulkan/include/vkn/type.h @@ -1,11 +1,10 @@ #pragma once -#include "pmr/frame_allocator.h" -#include "pmr/name.h" #include #include #define VK_NO_PROTOTYPES #include "volk/volk.h" #include "vma/vk_mem_alloc.h" +#include "render/render_type.h" #include "render/type.h" #define Z_RENDER_DEBUG 1 namespace vkn { @@ -16,7 +15,6 @@ namespace vkn { class CommandBuffer; using voidFn = std::function; using commandFn = std::function; - using api::TargetBufferFlags; using api::ResourceBarrierDesc; using api::TextureViewKey; using api::ImageViewPtr; @@ -50,28 +48,26 @@ namespace vkn { VmaAllocation indexAllocation; VmaAllocation vertexAllocation; }; + //不需要支持所有,只要支持常见的就行 struct RenderPassKey { - VkRenderPass pass; - VkFormat colorFormat[8]; - VkFormat depthFormat; - VkSampleCountFlagBits samples; - TargetBufferFlags clear; // 4 bytes - TargetBufferFlags discardStart; // 4 bytes - TargetBufferFlags discardEnd; // 4 bytes + TinyImageFormat colorFormat[MAX_SUPPORTED_RENDER_TARGET_COUNT]; + uint8_t depthMask; + uint8_t clear; // 1 bytes + uint8_t discardStart; // 1 bytes + uint8_t discardEnd; // 1 bytes + SampleCount samples; + uint8_t sampleMask;// 1 byte + uint8_t passMask;// 1 byte uint8_t subpassMask;// 1 byte - uint8_t initialColorLayoutMask;// 1 byte - uint8_t needsResolveMask; // 1 byte operator size_t() const{ return meta::MurmurHashFn(this); } }; struct RenderPassInfo { + VkRenderPass pass; RenderPassKey config; vector semaphores; vector commands; - VkRenderPass Pass() { - return config.pass; - } }; struct FramebufferKey { VkRenderPass pass; diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_api.h b/engine/modules/render/vulkan/include/vkn/vulkan_api.h index 2c2c8bd..0ba7732 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_api.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_api.h @@ -16,6 +16,7 @@ namespace vkn { using api::MaterialInstance; using api::RenderPassNode; using api::RenderPassType; + using api::RenderPassParams; class VULKAN_API VulkanAPI final : public api::RenderAPI{ private: VulkanWindow& window; diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_context.h b/engine/modules/render/vulkan/include/vkn/vulkan_context.h index 08317bf..5bd7399 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_context.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_context.h @@ -18,6 +18,7 @@ namespace vkn { void DrawIndexed(uint32_t index_count, uint32_t first_index, uint32_t first_vertex) override; void ExecuteSurfaceBarriers(const ResourceBarrierDesc& desc) override; + void ClearSurface(VkClearColorValue clearValue); void BeginRecord(VkCommandBufferUsageFlags flag); void EndRecord(VkQueue queue); }; diff --git a/engine/modules/render/vulkan/src/vulkan_api.cpp b/engine/modules/render/vulkan/src/vulkan_api.cpp index b095d29..2177c3c 100644 --- a/engine/modules/render/vulkan/src/vulkan_api.cpp +++ b/engine/modules/render/vulkan/src/vulkan_api.cpp @@ -89,7 +89,7 @@ namespace vkn { if (itPass == RenderPassCache.end()) { return; } - VkRenderPass renderpass = itPass->second.Pass(); + VkRenderPass renderpass = itPass->second.pass; pmr::vector shaderStages; std::map shaderModules; auto& device = backend.GetDevice(); @@ -365,35 +365,56 @@ namespace vkn { } void VulkanAPI::BeginRenderPass(RenderPassNode* node, FnEnterRenderPass callback) { - RenderPassKey config{}; - FramebufferKey frameKey{.layers = 1}; - VkClearValue clearValues[2 * MAX_SUPPORTED_RENDER_TARGET_COUNT + 1] = { 0 }; - int i = 0; + RenderPassKey config{}; + FramebufferKey frameKey{.layers = 1}; + VkClearValue clearValues[MAX_SUPPORTED_RENDER_TARGET_COUNT] = { 0 }; + RenderPassParams& params = node->params; + int clearSurfaceIndex = -1; + int i = 0, attachmentCount = 0; for (auto& it : node->outEdges) { - if (it->IsAttachment()) { - auto& desc = it->CastTo(); - TextureDesc& texture = desc.texture; - config.colorFormat[i] = (VkFormat)TinyImageFormat_ToVkFormat(texture.format); - config.samples = vkApiGetSmpleCountFlag(texture.sampleCount); - - TargetBufferFlags flag = TargetBufferFlags(int(TargetBufferFlags::COLOR0) << i); - config.clear |= flag; - desc.imageView = graph.ResolveTextureView(texture); - - frameKey.imageViews[i] = (VkImageView)desc.imageView; - frameKey.height = texture.height; - frameKey.width = texture.width; - - //clearValues[i] = - i++; + uint32_t flag = 1 << i; + TextureDesc& texture = it->CastTo(); + frameKey.imageViews[attachmentCount++] = (VkImageView)graph.ResolveTextureView(texture); + frameKey.height = texture.height; + frameKey.width = texture.width; + config.colorFormat[i] = texture.format; + if (params.sampleMask & flag) { + TextureDesc resolve = texture.Resolve(); + graph.AcquireTexture(resolve); + frameKey.imageViews[attachmentCount++] = (VkImageView)graph.ResolveTextureView(resolve); } + if (texture.sampleCount > config.samples) + config.samples = texture.sampleCount; + VkClearValue& clearValue = clearValues[i]; + const bool bclear = params.clear & flag; + if (texture.state == ResourceState::COLOR_ATTACHMENT) { + if (!bclear && context.surface.id == texture.id && node->IsFirstInput()) { + clearSurfaceIndex = i;//需要手动清除 + } + if (bclear || clearSurfaceIndex == i) { + clearValue.color.float32[0] = params.clearColor.r; + clearValue.color.float32[1] = params.clearColor.g; + clearValue.color.float32[2] = params.clearColor.b; + clearValue.color.float32[3] = params.clearColor.a; + } + } + else { + config.depthMask |= flag; + if (bclear) { + clearValue.depthStencil = { (float)params.clearDepth, params.clearStencil }; + } + } + i++; } - frameKey.attachmentCount = i; + frameKey.attachmentCount = attachmentCount; + config.clear = params.clear; + config.discardEnd = params.discardEnd; + config.discardStart = params.discardStart; RenderPassInfo* passInfo = GetRenderPassInfo(node->name, node->hash); if (!passInfo) { passInfo = GetRenderPassInfo(node->hash, config); } - frameKey.pass = passInfo->Pass(); + frameKey.pass = passInfo->pass; auto it = FramebufferCache.find(frameKey); VkFramebuffer framebuffer = it->second; if (it == FramebufferCache.end()) { @@ -428,6 +449,7 @@ namespace vkn { cmd.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); if(callback) callback(node); vkCmdBeginRenderPass(cmd.Ptr(), &beginInfo, VK_SUBPASS_CONTENTS_INLINE); + if (clearSurfaceIndex != -1)ctx.ClearSurface(clearValues[clearSurfaceIndex].color); } void VulkanAPI::EndRenderPass(RenderPassNode* node) { @@ -485,10 +507,10 @@ namespace vkn { } return nullptr; } + //单一renderpass,config.passMask 可以取 0 RenderPassInfo* VulkanAPI::GetRenderPassInfo(size_t& hash, const RenderPassKey& config) { hash = config; - auto it = RenderPassCache.find(hash); - if (it != RenderPassCache.end()) { + if (auto it = RenderPassCache.find(hash); it != RenderPassCache.end()) { return &it->second; } // Set up some const aliases for terseness. @@ -500,40 +522,34 @@ namespace vkn { VkAttachmentReference inputAttachmentRef[MAX_SUPPORTED_RENDER_TARGET_COUNT] = {}; VkAttachmentReference colorAttachmentRefs[2][MAX_SUPPORTED_RENDER_TARGET_COUNT] = {}; - VkAttachmentReference resolveAttachmentRef[MAX_SUPPORTED_RENDER_TARGET_COUNT] = {}; - VkAttachmentReference depthAttachmentRef = {}; - - const bool hasSubpasses = config.subpassMask != 0; - const bool hasDepth = config.depthFormat != VK_FORMAT_UNDEFINED; + VkAttachmentReference resolveAttachmentRef[2][MAX_SUPPORTED_RENDER_TARGET_COUNT] = {}; + VkAttachmentReference depthAttachmentRef[2] = {}; + const bool hasSubpasses = config.subpassMask; + const bool hasDepth1 = (!hasSubpasses && config.depthMask) || config.depthMask & config.passMask; + const bool hasDepth2 = config.depthMask & config.subpassMask; + const bool hasSample1 = (!hasSubpasses && config.sampleMask) || config.sampleMask & config.passMask; + const bool hasSample2 = config.sampleMask & config.subpassMask; VkSubpassDescription subpasses[2] = { { .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, .pInputAttachments = nullptr, .pColorAttachments = colorAttachmentRefs[0], - .pResolveAttachments = resolveAttachmentRef, - .pDepthStencilAttachment = hasDepth ? &depthAttachmentRef : nullptr + .pResolveAttachments = hasSample1 ? resolveAttachmentRef[0] : nullptr, + .pDepthStencilAttachment = hasDepth1 ? &depthAttachmentRef[0] : nullptr }, { .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, .pInputAttachments = inputAttachmentRef, .pColorAttachments = colorAttachmentRefs[1], - .pResolveAttachments = resolveAttachmentRef, - .pDepthStencilAttachment = hasDepth ? &depthAttachmentRef : nullptr + .pResolveAttachments = hasSample2 ? resolveAttachmentRef[1] : nullptr, + .pDepthStencilAttachment = hasDepth2 ? &depthAttachmentRef[1] : nullptr } }; - - // The attachment list contains: Color Attachments, Resolve Attachments, and Depth Attachment. - // For simplicity, create an array that can hold the maximum possible number of attachments. - // Note that this needs to have the same ordering as the corollary array in getFramebuffer. - VkAttachmentDescription attachments[MAX_SUPPORTED_RENDER_TARGET_COUNT + MAX_SUPPORTED_RENDER_TARGET_COUNT + 1] = {}; - + + VkAttachmentDescription attachments[MAX_SUPPORTED_RENDER_TARGET_COUNT] = {}; // We support 2 subpasses, which means we need to supply 1 dependency struct. VkSubpassDependency dependencies[1] = { { .srcSubpass = 0, .dstSubpass = 1, - .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - .dstAccessMask = VK_ACCESS_SHADER_READ_BIT, .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, } }; // Finally, create the VkRenderPass. @@ -544,127 +560,110 @@ namespace vkn { .subpassCount = hasSubpasses ? 2u : 1u, .pSubpasses = subpasses, .dependencyCount = hasSubpasses ? 1u : 0u, - .pDependencies = dependencies }; - int attachmentIndex = 0; + const VkSampleCountFlagBits samplecount = vkApiGetSmpleCountFlag(config.samples); + uint32_t attachmentIndex = 0, samplePassIndex1 = 0, samplePassIndex2 = 0; // Populate the Color Attachments. - for (int i = 0; i < MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) { - if (config.colorFormat[i] == VK_FORMAT_UNDEFINED) { - continue; + for (uint32_t i = 0; i < MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) { + if (config.colorFormat[i] == TinyImageFormat_UNDEFINED) { + break; } - const VkImageLayout subpassLayout = VK_IMAGE_LAYOUT_GENERAL; - uint32_t index; - - if (!hasSubpasses) { - index = subpasses[0].colorAttachmentCount++; - colorAttachmentRefs[0][index].layout = subpassLayout; - colorAttachmentRefs[0][index].attachment = attachmentIndex; - } - else { - - // The Driver API consolidates all color attachments from the first and second subpasses - // into a single list, and uses a bitmask to mark attachments that belong only to the - // second subpass and should be available as inputs. All color attachments in the first - // subpass are automatically made available to the second subpass. - - // If there are subpasses, we require the input attachment to be the first attachment. - // Breaking this assumption would likely require enhancements to the Driver API in order - // to supply Vulkan with all the information needed. - if (config.subpassMask & (1 << i)) { - index = subpasses[0].colorAttachmentCount++; - colorAttachmentRefs[0][index].layout = subpassLayout; - colorAttachmentRefs[0][index].attachment = attachmentIndex; - - index = subpasses[1].inputAttachmentCount++; - inputAttachmentRef[index].layout = subpassLayout; - inputAttachmentRef[index].attachment = attachmentIndex; - } - - index = subpasses[1].colorAttachmentCount++; - colorAttachmentRefs[1][index].layout = subpassLayout; - colorAttachmentRefs[1][index].attachment = attachmentIndex; - } - const TargetBufferFlags flag = TargetBufferFlags(int(TargetBufferFlags::COLOR0) << i); - const bool clear = any(config.clear & flag); - const bool discard = any(config.discardStart & flag); - VkImageLayout layout = vkApiGetAttachmentLayout(config.colorFormat[i], true); - attachments[attachmentIndex++] = { - .format = config.colorFormat[i], - .samples = config.samples, + const uint8_t flag = 1 << i; + const bool clear = config.clear & flag; + const bool discard = config.discardStart & flag; + const bool discardEnd = config.discardEnd & flag; + const bool sample = config.sampleMask & flag; + const VkFormat format = (VkFormat)TinyImageFormat_ToVkFormat(config.colorFormat[i]); + VkImageLayout layout = vkApiGetAttachmentLayout(format, true); + attachments[attachmentIndex] = { + .format = format, + .samples = sample ? samplecount : VK_SAMPLE_COUNT_1_BIT, .loadOp = clear ? kClear : (discard ? kDontCare : kKeep), - .storeOp = kEnableStore, + .storeOp = discardEnd ? kDisableStore : kEnableStore, .stencilLoadOp = kDontCare, .stencilStoreOp = kDisableStore, .initialLayout = layout, .finalLayout = layout, }; - } - // Nulling out the zero-sized lists is necessary to avoid VK_ERROR_OUT_OF_HOST_MEMORY on Adreno. - if (subpasses[0].colorAttachmentCount == 0) { - subpasses[0].pColorAttachments = nullptr; - subpasses[0].pResolveAttachments = nullptr; - subpasses[1].pColorAttachments = nullptr; - subpasses[1].pResolveAttachments = nullptr; - } - // Populate the Resolve Attachments. - VkAttachmentReference* pResolveAttachment = resolveAttachmentRef; - for (int i = 0; i < MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) { - if (config.colorFormat[i] == VK_FORMAT_UNDEFINED) { - continue; + if (sample) { + attachments[attachmentIndex + 1] = { + .format = format, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = clear ? kClear : (discard ? kDontCare : kKeep), + .storeOp = discardEnd ? kDisableStore : kEnableStore, + .stencilLoadOp = kDontCare, + .stencilStoreOp = kDisableStore, + .initialLayout = layout, + .finalLayout = layout, + }; } - - if (!(config.needsResolveMask & (1 << i))) { - pResolveAttachment->attachment = VK_ATTACHMENT_UNUSED; - ++pResolveAttachment; - continue; + const bool isDepth = config.depthMask & flag; + const bool isMask1 = !hasSubpasses || config.passMask & flag; + const bool isMask2 = hasSubpasses && config.subpassMask & flag; + uint32_t index = 0; + if (isMask1) { + index = subpasses[0].colorAttachmentCount++; + colorAttachmentRefs[0][index].layout = layout; + colorAttachmentRefs[0][index].attachment = attachmentIndex; + if (sample) { + index = subpasses[0].colorAttachmentCount++; + colorAttachmentRefs[0][index].layout = layout; + colorAttachmentRefs[0][index].attachment = attachmentIndex + 1; + } } - - pResolveAttachment->attachment = attachmentIndex; - pResolveAttachment->layout = VK_IMAGE_LAYOUT_GENERAL; - ++pResolveAttachment; - - attachments[attachmentIndex++] = { - .format = config.colorFormat[i], - .samples = VK_SAMPLE_COUNT_1_BIT, - .loadOp = kDontCare, - .storeOp = kEnableStore, - .stencilLoadOp = kDontCare, - .stencilStoreOp = kDisableStore, - .initialLayout = VK_IMAGE_LAYOUT_GENERAL, - .finalLayout = VK_IMAGE_LAYOUT_GENERAL, - }; - } - // Populate the Depth Attachment. - if (hasDepth) { - const bool clear = any(config.clear & TargetBufferFlags::DEPTH); - const bool discardStart = any(config.discardStart & TargetBufferFlags::DEPTH); - const bool discardEnd = any(config.discardEnd & TargetBufferFlags::DEPTH); - depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - depthAttachmentRef.attachment = attachmentIndex; - attachments[attachmentIndex++] = { - .format = config.depthFormat, - .samples = (VkSampleCountFlagBits)config.samples, - .loadOp = clear ? kClear : (discardStart ? kDontCare : kKeep), - .storeOp = discardEnd ? kDisableStore : kEnableStore, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - }; + if (isMask2) { + if (isMask1) { + index = subpasses[1].inputAttachmentCount++; + inputAttachmentRef[index].layout = layout; + inputAttachmentRef[index].attachment = sample ? attachmentIndex + 1 : attachmentIndex; + if (isDepth) { + dependencies->srcStageMask |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + dependencies->dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependencies->srcAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dependencies->dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + } + else { + dependencies->srcStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies->dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + dependencies->srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies->dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + } + } + else { + index = subpasses[1].colorAttachmentCount++; + colorAttachmentRefs[1][index].layout = layout; + colorAttachmentRefs[1][index].attachment = attachmentIndex; + if (sample) { + index = subpasses[1].colorAttachmentCount++; + colorAttachmentRefs[1][index].layout = layout; + colorAttachmentRefs[1][index].attachment = attachmentIndex + 1; + } + } + } + if (isDepth) { + if (isMask1) { + depthAttachmentRef[0].layout = layout; + depthAttachmentRef[0].attachment = attachmentIndex; + } + if (isMask2) { + depthAttachmentRef[1].layout = layout; + depthAttachmentRef[1].attachment = attachmentIndex; + } + } + attachmentIndex += sample ? 2 : 1; } + renderPassInfo.pDependencies = dependencies->srcStageMask ? dependencies : nullptr; renderPassInfo.attachmentCount = attachmentIndex; VkRenderPass pass; VkResult error = vkCreateRenderPass(backend.GetDevice().Ptr(), &renderPassInfo, nullptr, &pass); - RenderPassInfo info{ config}; - info.config.pass = pass; + RenderPassInfo info{pass, config}; backend.GetDevice().CreateSemaphores(info.semaphores, context.frameCount); Backend::RenderWorker->GetCommandPool().PopList(info.commands, context.frameCount); - RenderPassCache.emplace(hash, info); - return &RenderPassCache[hash]; + auto itr = RenderPassCache.emplace(hash, info); + return &itr.first->second; } void VulkanAPI::SetRenderPassInfo(Name name, VkRenderPass pass) { - RenderPassInfo info{}; - info.config.pass = pass; + RenderPassInfo info{pass}; backend.GetDevice().CreateSemaphores(info.semaphores, context.frameCount); Backend::RenderWorker->GetCommandPool().PopList(info.commands, context.frameCount); RenderPassNameCache.emplace(name, info); diff --git a/engine/modules/render/vulkan/src/vulkan_api_help.cpp b/engine/modules/render/vulkan/src/vulkan_api_help.cpp index 4b1e2be..e5556e9 100644 --- a/engine/modules/render/vulkan/src/vulkan_api_help.cpp +++ b/engine/modules/render/vulkan/src/vulkan_api_help.cpp @@ -1,4 +1,4 @@ -#include +#include "meta/enum.h" #include "vkn/vulkan_api_help.h" namespace vkn { VkImageLayout vkApiGetAttachmentLayout(VkFormat format, bool includeStencilBit) diff --git a/engine/modules/render/vulkan/src/vulkan_context.cpp b/engine/modules/render/vulkan/src/vulkan_context.cpp index acefd98..a34cce1 100644 --- a/engine/modules/render/vulkan/src/vulkan_context.cpp +++ b/engine/modules/render/vulkan/src/vulkan_context.cpp @@ -56,6 +56,23 @@ namespace vkn { VulkanAPI::Ptr()->ExecuteResourceBarriers(desc); EndRecord(Backend::RenderWorker->GetQueue().Ptr()); } + void VulkanContext::ClearSurface(VkClearColorValue clearValue) + { + // 条件满足时,手动清除附件 + VkClearAttachment clearAttachment = {}; + clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // 仅清除颜色附件 + clearAttachment.colorAttachment = 0; // 附件索引 + clearAttachment.clearValue.color = clearValue; // 传递清除值 + + VkClearRect clearRect = {}; + clearRect.rect.offset = { 0, 0 }; // 清除区域 + clearRect.rect.extent = { surface.width, surface.height }; // 渲染区域的大小 + clearRect.baseArrayLayer = 0; + clearRect.layerCount = 1; // 默认清除第一个层级 + + // 使用 vkCmdClearAttachments 清除颜色附件 + vkCmdClearAttachments(command, 1, &clearAttachment, 1, &clearRect); + } void VulkanContext::BeginRecord(VkCommandBufferUsageFlags flag) { VkCommandBufferBeginInfo beginInfo{ diff --git a/engine/modules/render/vulkan/src/vulkan_imgui_editor.cpp b/engine/modules/render/vulkan/src/vulkan_imgui_editor.cpp index b9e8aff..982a599 100644 --- a/engine/modules/render/vulkan/src/vulkan_imgui_editor.cpp +++ b/engine/modules/render/vulkan/src/vulkan_imgui_editor.cpp @@ -88,7 +88,8 @@ namespace vkn { Backend& backend = API->GetBackend(); Queue* pQueue = backend.GetDevice().GetQueue(Queue::RenderQueue); VkDescriptorPool descriptorPool = CreateDescriptorPool(backend.GetDevice().Ptr()); - VkRenderPass renderPass = CreateRenderPass(API->context.surface.format, backend.GetDevice().Ptr()); + TextureDesc surface = API->context.surface; + VkRenderPass renderPass = CreateRenderPass(surface.format, backend.GetDevice().Ptr()); ImGui_ImplVulkan_InitInfo init_info = {}; init_info.Instance = backend.GetInstance().Ptr(); @@ -152,10 +153,9 @@ namespace vkn { } void VulkanImguiEditor::Setup(FrameGraph& graph, RenderPassBuilder& builder) { - AttachmentDesc surface{ graph.GetRenderSurface() }; builder.Name(ImguiPassName) .Type(RenderPassNodeType::Imgui, RenderPassNodeFlag::Output) - .Write(surface, ResourceState::COLOR_ATTACHMENT); + .Write(graph.GetRenderSurface(), ResourceState::COLOR_ATTACHMENT); if (gEngineConfig.IsRenderEditorSurface) { builder.Read(graph.GetSurface(), ResourceState::READ_ONLY); } diff --git a/engine/src/editor/panel/asset_preview_panel.cpp b/engine/src/editor/panel/asset_preview_panel.cpp index 16f26f4..a1a9ce3 100644 --- a/engine/src/editor/panel/asset_preview_panel.cpp +++ b/engine/src/editor/panel/asset_preview_panel.cpp @@ -2,7 +2,15 @@ #include "data/global.h" #include namespace api { - TextureSampler sampler; + TextureSampler sampler{ + .filterMag = SamplerMagFilter::LINEAR, + .filterMin = SamplerMinFilter::LINEAR, + .wrapS = SamplerWrapMode::CLAMP_TO_EDGE, + .wrapT = SamplerWrapMode::CLAMP_TO_EDGE, + .wrapR = SamplerWrapMode::CLAMP_TO_EDGE, + .compareMode = SamplerCompareMode::COMPARE_TO_TEXTURE, + .compareFunc = SamplerCompareFunc::GE, + }; ImTextureID TextureIDList[10] = {}; void AssetPreviewPanel::DrawPanel(FrameGraph& graph, RenderEditorContext& context) { static float my_float = 0.5f; diff --git a/game/zworld/imgui.ini b/game/zworld/imgui.ini index b4ee362..b82a71a 100644 --- a/game/zworld/imgui.ini +++ b/game/zworld/imgui.ini @@ -1,6 +1,5 @@ [Window][Debug##Default] -ViewportPos=480,240 -ViewportId=0x16723995 +Pos=60,60 Size=400,400 Collapsed=0 @@ -11,9 +10,8 @@ Size=191,71 Collapsed=0 [Window][MainWindow] -ViewportPos=480,240 -ViewportId=0x72FC8CA3 -Size=191,105 +Pos=163,77 +Size=695,351 Collapsed=0 [Docking][Data] diff --git a/game/zworld/src/zworld.cpp b/game/zworld/src/zworld.cpp index cf2d6a1..e41d54e 100644 --- a/game/zworld/src/zworld.cpp +++ b/game/zworld/src/zworld.cpp @@ -45,6 +45,9 @@ void ZWorldModule::MainLoop() while (running) { // 处理事件 while (SDL_PollEvent(&event_)) { +#ifdef WITH_EDITOR + ImGui_ImplSDL2_ProcessEvent(&event_); +#endif // WITH_EDITOR if (event_.type == SDL_QUIT) { running = false; }