rebuild framegraph resource system

This commit is contained in:
ouczbs 2024-12-19 17:23:52 +08:00
parent 99803e7391
commit fef024d407
35 changed files with 424 additions and 357 deletions

View File

@ -3,6 +3,6 @@
namespace api {
class AssetPreviewPanel : public EditorPanel{
public:
void DrawPanel() override;
void DrawPanel(FrameGraph& graph, RenderEditorContext& context) override;
};
}

View File

@ -3,6 +3,6 @@
namespace api {
class MenuBarPanel : public EditorPanel {
public:
void DrawPanel() override;
void DrawPanel(FrameGraph& graph, RenderEditorContext& context) override;
};
}

View File

@ -4,6 +4,6 @@ namespace api {
class EditorMainWindow : public EditorWindow {
public:
EditorMainWindow();
void Draw() override;
void Draw(FrameGraph& graph, RenderEditorContext& context) override;
};
}

View File

@ -3,5 +3,9 @@
namespace api{
struct EngineConfig {
GraphicsAPI API = GraphicsAPI::Vulkan;
#ifdef WITH_EDITOR
bool IsRenderEditorSurface = false;
#endif // WITH_EDITOR
};
}

View File

@ -22,7 +22,7 @@ namespace api{
static std::function<R(Args...)> EasyBind(R(Type::* func)(Args... args) const, const Type* invoker) {
return [=](auto&&... args) {
return (invoker->*func)(std::forward<decltype(args)>(args)...);
};
};
}
public:
Event(Name name) : name(name){};

View File

@ -2,12 +2,13 @@
#include "event.h"
#include "module/module.h"
namespace api {
class FrameGraph;
class APP_API EventSystem : public ISystem{
SINGLETON_IMPL(EventSystem)
public:
EventSystem();
void Initialize() override;
void Finalize() override;
Event<void()> BeginRenderFrame{"BeginRenderFrame"};
Event<void(FrameGraph&, uint32_t)> BeginRenderFrame{"BeginRenderFrame"};
};
}

View File

@ -229,7 +229,7 @@
*
*
*/
typedef enum TinyImageFormat {
typedef enum TinyImageFormat : uint8_t{
TinyImageFormat_UNDEFINED = 0,
TinyImageFormat_R1_UNORM = 1,
TinyImageFormat_R2_UNORM = 2,

View File

@ -22,6 +22,7 @@ namespace api {
}
void RenderAPI::Render()
{
graph.Setup();
for (auto view : context.views) {
RenderView(view);
}

View File

@ -1,12 +1,17 @@
#pragma once
#ifdef WITH_EDITOR
#include "graph/frame_graph.h"
#include "module/module_manager.h"
#include <imgui.h>
namespace api {
class RenderEditorContext {
};
class EditorPanel {
public:
EditorPanel() = default;
~EditorPanel() = default;
virtual void DrawPanel() = 0;
virtual void DrawPanel(FrameGraph& graph, RenderEditorContext& ctx) = 0;
};
class EditorWindow {
protected:
@ -14,7 +19,7 @@ namespace api {
public:
EditorWindow() = default;
~EditorWindow() = default;
virtual void Draw() = 0;
virtual void Draw(FrameGraph& graph, RenderEditorContext& ctx) = 0;
template<typename T, typename ... Args>
T* AddPanel(Args&&... args) {
T* ptr = new (GlobalPool()) T(std::forward<Args>(args)...);
@ -35,6 +40,7 @@ namespace api {
mWindows.push_back(ptr);
return ptr;
}
virtual ImTextureID AddTexture(const TextureDesc& desc) = 0;
};
}
#endif // WITH_EDITOR

View File

@ -2,37 +2,47 @@
#include "type.h"
namespace api {
struct FRenderView;
using pmr::Tag;
class FrameGraph
{
public:
class TextureBuilder;
class RenderPassBuilder;
public:
inline static Name NameSurface{ "surface" };
TextureDesc mSurface{};
table<Tag, TextureDesc> mTextureTagMap;
table<TextureKey, uint32_t> mTextureKeyMap;
std::vector<TextureDesc> mTexturePool;
table<TextureViewKey, ImageViewPtr> mTextureViewPool;
pmr::vector<FrameGraphNodePtr> mNodes{FramePool()};
RenderPassNode* mFirstInputNode{ nullptr };
RenderPassNode* mLastOutputNode{ nullptr };
TextureDesc mSurface;
table<Name, TextureDesc> mTextureTable;
table<TextureDesc, ImagePtr> mTexturePool;
table<TextureViewDesc, ImageViewPtr> mTextureViewPool;
pmr::vector<FrameGraphNodePtr> mNodes{FramePool()};
inline static Name NameSurface{ "surface" };
#ifdef WITH_EDITOR
inline static Name NameEditorSurface{ "editor_surface" };
TextureDesc mEditorSurface{};
bool mIsRenderEditorSurface{false};
#endif //
public:
template<typename T>
FrameGraphNodePtr AddRenderPass() { return AddRenderPass(&T::Setup, &T::Execute); }
using RenderPassSetupFunction = std::function<void(FrameGraph&, RenderPassBuilder&)>;
FrameGraphNodePtr AddRenderPass(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor);
TextureBuilder CreateTextureBuild();
void InitSurface(span<TextureDesc> surfaces);
RenderPassBuilder CreateRenderPassBuild();
void InitSurface(TextureDesc* surfaces, uint32_t frames);
void Input(const TextureDesc& surfaces) { mSurface = surfaces; };
void Setup();
void Compile();
void Execute(FRenderView& view);
void Clear();
void CullGraph();
void FillGraph();
ResourceState Resolve(Name name,TextureDesc& desc, ResourceState state);
ResourceState Resolve(Name name, AttachmentDesc& desc, ResourceState state);
ResourceState Resolve(Name name, BufferDesc& desc, ResourceState state);
ImagePtr ResolveTexture(TextureDesc desc);
ImageViewPtr ResolveTextureView(TextureViewDesc desc);
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 ResourceTexture(Name name, int num);
ImageViewPtr ResolveTextureView(TextureDesc& desc);
ImageViewPtr ResolveTextureView(TextureViewKey key);
void ResourceTexture(TextureDesc& desc);
void SetResourceTexture(TextureDesc texture, Name name, int num = 0);
public:
void ExecutePresentPass(FRenderView& view);
void ExecuteRenderPass(RenderPassNode* node, FRenderView& view);

View File

@ -1,26 +1,16 @@
#pragma once
namespace api {
struct FrameGraph::RenderPassBuilder {
struct RenderPassBuilder {
FrameGraph& graph;
FrameGraphNodePtr& node;
FrameResource* resource;
FrameGraphNodePtr node;
FrameResource* resource{nullptr};
public:
RenderPassBuilder(FrameGraph* graph) noexcept
: graph(*graph), node() {};
RenderPassBuilder(FrameGraph* graph, FrameGraphNodePtr& node) noexcept
: graph(*graph) , node(node) {};
FrameGraph::RenderPassBuilder& Name(pmr::Name name);
FrameGraph::RenderPassBuilder& Type(RenderPassNodeType type,RenderPassNodeFlag flag = RenderPassNodeFlag::None);
FrameGraph::RenderPassBuilder& Read(TextureDesc desc, ResourceState state);
FrameGraph::RenderPassBuilder& Write(BufferDesc desc, ResourceState state);
FrameGraph::RenderPassBuilder& Attach(AttachmentDesc desc, ResourceState state);
FrameGraph::RenderPassBuilder& Read(const FrameGraphEdgePtr& refEdge, ResourceState state);
FrameGraph::RenderPassBuilder& Write(const FrameGraphEdgePtr& refEdge, ResourceState state);
};
struct FrameGraph::TextureBuilder {
FrameGraph& graph;
FrameGraphEdgePtr edge;
public:
TextureBuilder(FrameGraph* graph)noexcept : graph(*graph) { edge.Make(); };
FrameGraph::TextureBuilder& Import(pmr::Name name, AttachmentDesc desc);
FrameGraphEdgePtr Edge() const { return edge; }
RenderPassBuilder& Name(pmr::Name name);
RenderPassBuilder& Type(RenderPassNodeType type,RenderPassNodeFlag flag = RenderPassNodeFlag::None);
RenderPassBuilder& Write(AttachmentDesc desc, ResourceState state, pmr::Name name = {});
};
}

View File

@ -3,6 +3,8 @@
#include "render/type.h"
#include <functional>
namespace api {
class FrameGraph;
class RenderPassBuilder;
struct RenderPassNode;
struct RenderContext;
struct ComputePassContext {};
@ -16,20 +18,17 @@ namespace api {
size_t PassKey()const;
};
struct CopyPassContext {};
class FrameGraph;
using RenderPassSetupFunction = std::function<void(FrameGraph&, RenderPassBuilder&)>;
using CopyPassExecuteFunction = std::function<void(FrameGraph&, CopyPassContext&)>;
using ComputePassExecuteFunction = std::function<void(FrameGraph&, ComputePassContext&)>;
using RenderPassExecuteFunction = std::function<void(FrameGraph&, RenderPassContext&)>;
using RenderPassNodeExecuteFn = std::variant<RenderPassExecuteFunction, ComputePassExecuteFunction, CopyPassExecuteFunction>;
class RenderPass;
class RenderPassNode;
struct FrameGraphNodePtr {
using NodeType = RenderPassType;
RenderPassNode* node;
NodeType type{ NodeType::Render };
FrameGraphNodePtr() : node(nullptr){};
FrameGraphNodePtr(const RenderPassNodeExecuteFn& executor, NodeType type = NodeType::Render);
FrameGraphNodePtr(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor, NodeType type = NodeType::Render);
operator bool() const {
return node;
}
@ -40,65 +39,48 @@ namespace api {
struct FrameResource {
using Resource = std::variant<TextureDesc, BufferDesc, AttachmentDesc>;
Name name;
Resource resource;
FrameGraphNodePtr source;
pmr::vector<FrameGraphNodePtr> targets{ FramePool() };
Resource res;
RenderPassNode* node;
FrameResource() noexcept = default;
FrameResource(Name name,const Resource& res, RenderPassNode* node) : name(name), res(res), node(node){};
template<typename T>
T& CastTo() {
return std::get<T>(resource);
return std::get<T>(res);
}
bool IsAttachment() const {
return std::holds_alternative<AttachmentDesc>(resource);
return std::holds_alternative<AttachmentDesc>(res);
}
bool IsTexture() const{
return std::holds_alternative<TextureDesc>(resource);
return std::holds_alternative<TextureDesc>(res);
}
bool IsBuffer() const {
return std::holds_alternative<BufferDesc>(resource);
return std::holds_alternative<BufferDesc>(res);
}
static FrameResource* Make(Name name, const Resource& res, RenderPassNode* node) {
return new(FramePool()) FrameResource(name, res, node);
}
};
struct FrameGraphEdgePtr {
ResourceState targetState;
FrameResource* resource;
FrameGraphEdgePtr() = default;
FrameGraphEdgePtr(const FrameGraphEdgePtr& edge, ResourceState state) {
targetState = state;
resource = edge.resource;
}
FrameResource* Make() {
resource = new (FramePool()) FrameResource();
return resource;
}
RenderPassNode* SourceNode()const {
return resource->source.node;
}
operator bool() const{
return resource;
}
FrameResource* operator ->()const {
return resource;
}
void ResolveView(FrameGraph* graph);
};
enum class RenderPassNodeType : uint16_t {
using FrameGraphEdgePtr = FrameResource*;
enum class RenderPassNodeType : uint8_t {
None,
Scene,
Imgui,
};
enum class RenderPassNodeFlag : uint16_t
enum class RenderPassNodeFlag : uint8_t
{
None = 0,
Output = 0x01,
FirstInput = 0x02,
LastOutput = 0x04,
};
using RenderPassEdgeIterFn = std::function<void(FrameResource*, FrameGraphEdgePtr)>;
using RenderPassEdgeIterFn = std::function<void(FrameResource*)>;
struct RenderPassNode {
Name name;
size_t hash{0};
RenderPassNodeType type{0};
RenderPassNodeFlag flag{0};
bool isActive{ false };
RenderPassSetupFunction setup;
RenderPassNodeExecuteFn executor;
pmr::vector<RenderPassNode*> dependencies{ FramePool() };
pmr::vector<FrameGraphEdgePtr> inEdges{ FramePool() };
@ -112,7 +94,7 @@ namespace api {
FrameGraphEdgePtr FindInput(Name name)
{
for (auto& edge : inEdges) {
if (edge.resource->name == name) {
if (edge->name == name) {
return edge;
}
}
@ -121,19 +103,13 @@ namespace api {
FrameGraphEdgePtr FindOutput(Name name)
{
for (auto& edge : outEdges) {
if (edge.resource->name == name) {
if (edge->name == name) {
return edge;
}
}
return {};
}
};
inline FrameGraphNodePtr::FrameGraphNodePtr(const RenderPassNodeExecuteFn& executor, NodeType type)
: type(type)
{
node = new (FramePool()) RenderPassNode();
node->executor = executor;
}
inline size_t RenderPassContext::PassKey()const
{
return node->hash;

View File

@ -4,7 +4,7 @@
namespace api {
class DemoPass : public RenderPass {
public:
static void Setup(FrameGraph& graph, FrameGraph::RenderPassBuilder& builder);
static void Setup(FrameGraph& graph, RenderPassBuilder& builder);
static void Execute(FrameGraph&, RenderPassContext&);
};

View File

@ -33,8 +33,8 @@ namespace api {
virtual void LoadShader(Shader& shader, size_t passKey) = 0;
virtual void CreateBuffer(BufferDesc& desc) = 0;
virtual ImagePtr CreateTexture(TextureDesc desc) = 0;
virtual ImageViewPtr CreateTextureView(TextureViewDesc desc) = 0;
virtual void CreateTexture(TextureDesc& desc) = 0;
virtual ImageViewPtr CreateTextureView(TextureViewKey desc) = 0;
virtual void BeginFrame() = 0;
virtual void EndFrame() = 0;

View File

@ -6,7 +6,7 @@
//#include <algorithm>
namespace api {
using pmr::Name;
enum class GraphicsAPI
enum class GraphicsAPI : uint8_t
{
OpenGL,
Vulkan,
@ -18,14 +18,14 @@ namespace api {
Compute,
Copy
};
enum class BufferUsage {
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
enum class ResourceMemoryUsage : uint8_t
{
/// No intended memory usage specified.
UNKNOWN = 0,
@ -39,7 +39,7 @@ namespace api {
GPU_TO_CPU = 4,
COUNT,
};
enum SampleCount
enum SampleCount : uint8_t
{
SAMPLE_COUNT_1 = 1,
SAMPLE_COUNT_2 = 2,
@ -66,7 +66,7 @@ namespace api {
DEPTH_AND_STENCIL = DEPTH | STENCIL, //!< depth and stencil buffer selected.
ALL = COLOR_ALL | DEPTH | STENCIL //!< Color, depth and stencil buffer selected.
};
enum class ResourceState
enum class ResourceState : uint8_t
{
// The initial layout after the creation of the VkImage. We use this to denote the state before
// any transition.
@ -89,7 +89,20 @@ namespace api {
// TODO: explore separate layout policies for attachment+sampling and just attachment.
COLOR_ATTACHMENT,
};
enum class TextureDimension
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,
@ -101,7 +114,7 @@ namespace api {
UNIFORM_BUFFER,
SAMPLER,
};
enum class ShaderStage : uint32_t {
enum class ShaderStage : uint8_t {
NONE = 0,
VERTEX = 0x1,
FRAGMENT = 0x2,
@ -188,28 +201,33 @@ namespace api {
}
BufferBarrier ToBarrier(ResourceState from, ResourceState to)const;
};
struct TextureViewDesc {
struct TextureViewKey {
ImagePtr image;
TinyImageFormat format : 16;
TextureDimension dimension : 8;
uint32_t baseArrayLayer : 8;
uint32_t layerCount : 8;
uint32_t baseMipLevel : 8;
uint32_t levelCount : 8;
TinyImageFormat format;
TextureDimension dimension;
uint8_t baseArrayLayer;
uint8_t layerCount;
uint8_t baseMipLevel;
uint8_t levelCount;
};
struct TextureDesc {
ImagePtr image;
uint32_t width;
uint32_t height;
uint32_t depth : 16;
TinyImageFormat format : 16;
ResourceState state : 8;
SampleCount sampleCount : 8;
uint32_t arraySize : 8;
TextureDimension dimension : 4;
uint32_t mipLevel : 4;
TextureViewDesc ToTextureView() const{
TextureViewDesc desc{};
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;
};
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;
@ -222,39 +240,12 @@ namespace api {
TextureBarrier ToBarrier(ResourceState from, ResourceState to)const;
};
struct AttachmentDesc {
ImagePtr image;
TextureDesc texture;
ImageViewPtr imageView;
uint32_t width;
uint32_t height;
TextureDimension dimension : 16;
TinyImageFormat colorFormat : 16;
SampleCount sampleCount : 16;
AttachmentDesc& FromTexture(const TextureDesc& desc) {
width = desc.width;
height = desc.height;
image = desc.image;
sampleCount = desc.sampleCount;
colorFormat = desc.format;
dimension = desc.dimension;
return *this;
}
TextureDesc ToTexture() const {
return TextureDesc{
.image = image,
.width = width,
.height = height,
};
}
TextureViewDesc ToTextureView() const {
TextureViewDesc desc{};
desc.image = image;
desc.format = colorFormat;
desc.baseArrayLayer = 0;
desc.baseMipLevel = 0;
desc.layerCount = 1;
desc.levelCount = 1;
desc.dimension = dimension;
return desc;
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;
};
@ -309,10 +300,10 @@ namespace api {
TextureBarrier barrier{};
barrier.mSrcState = from;
barrier.mDstState = to;
barrier.mTexture = ToTexture();
barrier.mTexture = texture;
return barrier;
}
inline bool operator==(const TextureViewDesc& k1, const TextureViewDesc& k2) {
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;
@ -322,11 +313,9 @@ namespace api {
if (k1.levelCount != k2.levelCount) return false;
return true;
}
inline bool operator==(const TextureDesc& k1, const TextureDesc& k2) {
if (k1.image != k2.image) return false;
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.state != k2.state) return false;
if (k1.width != k2.width) return false;
if (k1.height != k2.height) return false;
if (k1.arraySize != k2.arraySize) return false;
@ -339,17 +328,17 @@ namespace api {
#include "meta/hash.h"
namespace std {
template<>
struct hash<api::TextureViewDesc>
struct hash<api::TextureViewKey>
{
size_t operator()(const api::TextureViewDesc& key) const noexcept
size_t operator()(const api::TextureViewKey& key) const noexcept
{
return meta::MurmurHashFn(key);
}
};
template<>
struct hash<api::TextureDesc>
struct hash<api::TextureKey>
{
size_t operator()(const api::TextureDesc& key) const noexcept
size_t operator()(const api::TextureKey& key) const noexcept
{
return meta::MurmurHashFn(key);
}

View File

@ -4,26 +4,32 @@
#include <unordered_set>
#include <algorithm>
namespace api {
//先准备再执行,这样就可以在执行之前,做一些特殊的资源初始化工作
FrameGraphNodePtr FrameGraph::AddRenderPass(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor)
{
FrameGraphNodePtr node_ptr{executor };
RenderPassBuilder builder{ this, node_ptr };
setup(*this, builder);
FrameGraphNodePtr node_ptr{ setup, executor};
mNodes.push_back(node_ptr);
return node_ptr;
}
FrameGraph::TextureBuilder FrameGraph::CreateTextureBuild()
RenderPassBuilder FrameGraph::CreateRenderPassBuild()
{
return TextureBuilder{this};
return RenderPassBuilder{this};
}
void FrameGraph::InitSurface(span<TextureDesc> surfaces)
void FrameGraph::InitSurface(TextureDesc* surfaces, uint32_t frames)
{
mSurface = surfaces[0];
RenderAPI* API = RenderAPI::Ptr();
for (auto& surface : surfaces) {
TextureViewDesc desc = surface.ToTextureView();
//ImageViewPtr view = API->CreateTextureView(desc);
//mResourceViewPool.emplace(desc, view);
mTexturePool.reserve(frames);
for (uint32_t i = 0; i < frames;i++) {
surfaces[i].id = mTexturePool.size() + 1;
mTexturePool.push_back(surfaces[i]);
}
}
void FrameGraph::Setup()
{
uint32_t size = mNodes.size();
for (uint32_t i = 0; i < size;i++) {
auto& node = mNodes[i];//mNodes 数量可能会增加
RenderPassBuilder builder{this, node};
node->setup(*this, builder);
}
}
void FrameGraph::Compile()
@ -42,6 +48,12 @@ namespace api {
if ((!mLastOutputNode || node->type > mLastOutputNode->type)) {
mLastOutputNode = node.node;
}
if ((!mFirstInputNode || node->type < mFirstInputNode->type)) {
#ifdef WITH_EDITOR
if(!mIsRenderEditorSurface || node->type >= RenderPassNodeType::Imgui)
#endif // WITH_EDITOR
mFirstInputNode = node.node;
}
}
}
while (!stack.empty()) {
@ -51,15 +63,10 @@ namespace api {
continue;
}
node->isActive = true;
bool isInput = node->IsOutput();
for (auto& edge : node->inEdges) {
if (!edge->source->isActive) {
stack.push(edge.SourceNode());
if (edge->node && !edge->node->isActive) {
stack.push(edge->node);
}
isInput = isInput || edge->name == NameSurface;
}
if (isInput && (!mFirstInputNode || node->type < mFirstInputNode->type)) {
mFirstInputNode = node;
}
}
auto end = std::remove_if(mNodes.begin(), mNodes.end(), [this](FrameGraphNodePtr& node) {
@ -86,8 +93,8 @@ namespace api {
seenNodes.insert(node->dependencies[0]);
}
for (auto& edge : node->inEdges) {
RenderPassNode* srcNode = edge.SourceNode();
if (seenNodes.insert(srcNode).second) {
RenderPassNode* srcNode = edge->node;
if (srcNode && seenNodes.insert(srcNode).second) {
node->dependencies.push_back(srcNode);
}
}
@ -134,18 +141,25 @@ namespace api {
}
void FrameGraph::ExecutePresentPass(FRenderView& view)
{
if (mSurface.state == ResourceState::PRESENT) {
#ifdef WITH_EDITOR
TextureDesc& surface = ResolveTexture(mIsRenderEditorSurface ? mEditorSurface : mSurface);
#else
TextureDesc& surface = ResolveTexture(mSurface);
#endif // WITH_EDITOR
if (surface.state == ResourceState::PRESENT) {
surface.state = ResourceState::UNDEFINED;
return;
}
TextureBarrier barrier{};
barrier.mSrcState = mSurface.state;
barrier.mSrcState = surface.state;
barrier.mDstState = ResourceState::PRESENT;
barrier.mTexture = mSurface;
barrier.mTexture = surface;
ResourceBarrierDesc desc{};
desc.type = RenderPassType::Present;
desc.textureBarriersCount = 1;
desc.pTextureBarriers = &barrier;
view.context->ExecuteSurfaceBarriers(desc);
surface.state = ResourceState::UNDEFINED;
}
void FrameGraph::ExecuteComputePass(RenderPassNode* node, FRenderView& view)
{
@ -162,12 +176,11 @@ namespace api {
pmr::vector<BufferBarrier> bufferBarrier{FramePool()};
pmr::vector<TextureBarrier> textureBarrier{ FramePool() };
auto graph = &RenderAPI::Ptr()->graph;
node->ForeachEdge([&](FrameResource* resource, FrameGraphEdgePtr edge) {
node->ForeachEdge([&](FrameResource* resource) {
std::visit([&](auto& desc) {
ResourceState targetState = edge.targetState;
ResourceState sourceState = graph->Resolve(resource->name, desc, targetState);
if (sourceState != targetState) {
auto barrier = desc.ToBarrier(sourceState, targetState);
ResourceState srcstate, dststate;
if (!graph->ResolveState(desc, srcstate, dststate)) {
auto barrier = desc.ToBarrier(srcstate, dststate);
using T = decltype(barrier);
if constexpr (std::is_same_v<T, BufferBarrier>) {
bufferBarrier.push_back(barrier);
@ -176,7 +189,7 @@ namespace api {
textureBarrier.push_back(barrier);
}
}
}, resource->resource);
}, resource->res);
});
if (bufferBarrier.empty() && textureBarrier.empty()) {
return;
@ -189,47 +202,104 @@ namespace api {
desc.pTextureBarriers = textureBarrier.data();
RenderAPI::Ptr()->ExecuteResourceBarriers(desc);
}
ResourceState FrameGraph::Resolve(Name name, TextureDesc& desc, ResourceState state)
void FrameGraph::TransitionState(TextureDesc& desc, ResourceState state)
{
ResourceState sourceState = ResourceState::UNDEFINED;
if (name == NameSurface) {
mSurface = desc;
}
return sourceState;
}
ResourceState FrameGraph::Resolve(Name name, AttachmentDesc& desc, ResourceState state)
{
ResourceState sourceState = ResourceState::UNDEFINED;
if (name == NameSurface) {
sourceState = mSurface.state;
TextureDesc& texture = ResolveTexture(desc);
desc.state = state;
texture.state = state;
if (texture.id == mSurface.id) {
mSurface.state = state;
return sourceState;
}
return sourceState;
}
ResourceState FrameGraph::Resolve(Name name, BufferDesc& desc, ResourceState state)
{
ResourceState sourceState = ResourceState::UNDEFINED;
return sourceState;
}
ImagePtr FrameGraph::ResolveTexture(TextureDesc desc)
{
auto it = mTexturePool.find(desc);
if (it != mTexturePool.end()) {
return it->second;
#ifdef WITH_EDITOR
else if (texture.id == mEditorSurface.id) {
mEditorSurface.state = state;
}
ImagePtr image = RenderAPI::Ptr()->CreateTexture(desc);
mTexturePool.emplace(desc, image);
return image;
#endif // WITH_EDITOR
}
ImageViewPtr FrameGraph::ResolveTextureView(TextureViewDesc desc)
bool FrameGraph::ResolveState(TextureDesc& desc, ResourceState& srcstart, ResourceState& dststate)
{
auto it = mTextureViewPool.find(desc);
TextureDesc& texture = ResolveTexture(desc);
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
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;
}
TextureDesc& FrameGraph::ResolveTexture(TextureDesc& desc)
{
if (!desc.id || desc.id > mTexturePool.size()) {
return desc;
}
TextureDesc& texture = mTexturePool[desc.id - 1];
if (!texture.image) {
RenderAPI::Ptr()->CreateTexture(texture);
}
return texture;
}
ImageViewPtr FrameGraph::ResolveTextureView(TextureDesc& desc)
{
if (!desc.image) {
desc = ResolveTexture(desc);
}
return ResolveTextureView(desc.ToTextureView());
}
ImageViewPtr FrameGraph::ResolveTextureView(TextureViewKey key)
{
auto it = mTextureViewPool.find(key);
if (it != mTextureViewPool.end()) {
return it->second;
}
ImageViewPtr view = RenderAPI::Ptr()->CreateTextureView(desc);
mTextureViewPool.emplace(desc, view);
ImageViewPtr view = RenderAPI::Ptr()->CreateTextureView(key);
mTextureViewPool.emplace(key, view);
return view;
}
TextureDesc FrameGraph::ResourceTexture(Name name, int num)
{
Tag tag(name, num);
auto it = mTextureTagMap.find(tag);
if (it != mTextureTagMap.end()) {
return it->second;
}
return TextureDesc{};
}
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);
}
}
void FrameGraph::SetResourceTexture(TextureDesc desc, Name name, int num)
{
if (!desc.id) {
desc.id = mTexturePool.size() + 1;
mTexturePool.push_back(desc);
}
Tag tag(name, num);
//auto it = mTextureTagMap.find(tag);
//if (it != mTextureTagMap.end()) {
//todo: destroy texture
//}
mTextureTagMap[tag] = desc;
}
}

View File

@ -1,70 +1,24 @@
#include "render/graph/frame_graph.h"
#include "render/pass/render_pass.h"
namespace api {
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Name(pmr::Name name)
RenderPassBuilder& RenderPassBuilder::Name(pmr::Name name)
{
node->name = name;
return *this;
}
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Type(RenderPassNodeType type, RenderPassNodeFlag flag)
RenderPassBuilder& RenderPassBuilder::Type(RenderPassNodeType type, RenderPassNodeFlag flag)
{
node->type = type;
node->flag = flag;
return *this;
}
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Read(TextureDesc desc, ResourceState state)
{
FrameGraphEdgePtr edge{};
edge.targetState = state;
resource = edge.Make();
resource->source = node;
resource->resource = desc;
node->inEdges.push_back(edge);
return *this;
}
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Write(BufferDesc desc, ResourceState state)
RenderPassBuilder& RenderPassBuilder::Write(AttachmentDesc desc, ResourceState state, pmr::Name name)
{
FrameGraphEdgePtr edge{};
edge.targetState = state;
resource = edge.Make();
resource->source = node;
resource->resource = desc;
desc.texture.state = state;
FrameGraphEdgePtr edge = FrameResource::Make(name, desc, node.node);
node->outEdges.push_back(edge);
return *this;
}
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Attach(AttachmentDesc desc, ResourceState state)
{
FrameGraphEdgePtr edge{};
edge.targetState = state;
resource = edge.Make();
resource->source = node;
resource->resource = desc;
node->outEdges.push_back(edge);
return *this;
}
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Read(const FrameGraphEdgePtr& refEdge, ResourceState state)
{
if (!refEdge) { return *this; }
FrameGraphEdgePtr edge{ refEdge , state};
node->inEdges.emplace_back(edge);
refEdge->targets.emplace_back(node);
return *this;
}
FrameGraph::RenderPassBuilder& FrameGraph::RenderPassBuilder::Write(const FrameGraphEdgePtr& refEdge, ResourceState state)
{
if (!refEdge) { return *this; }
FrameGraphEdgePtr edge{ refEdge , state };
node->outEdges.emplace_back(edge);
refEdge->targets.emplace_back(node);
return *this;
}
FrameGraph::TextureBuilder& FrameGraph::TextureBuilder::Import(pmr::Name name, AttachmentDesc desc)
{
edge->name = name;
edge->resource = desc;
return *this;
}
}

View File

@ -1,20 +1,18 @@
#include "render/graph/type.h"
#include "render/renderapi.h"
namespace api {
void FrameGraphEdgePtr::ResolveView(FrameGraph* graph)
{
if (resource->IsAttachment()) {
AttachmentDesc& attach = resource->CastTo<AttachmentDesc>();
TextureViewDesc desc = attach.ToTextureView();
attach.imageView = graph->ResolveTextureView(desc);
}
}
void RenderPassNode::ForeachEdge(RenderPassEdgeIterFn fn) {
for (auto& edge : inEdges) {
fn(edge.resource, edge);
fn(edge);
}
for (auto& edge : outEdges) {
fn(edge.resource, edge);
fn(edge);
}
}
FrameGraphNodePtr::FrameGraphNodePtr(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor, NodeType type) : type(type)
{
node = new (FramePool()) RenderPassNode();
node->setup = setup;
node->executor = executor;
}
}

View File

@ -9,16 +9,12 @@ namespace api {
static RscHandle<Material> material;
static RscHandle<Shader> shader;
static RscHandle<Mesh> mesh;
void DemoPass::Setup(FrameGraph& graph, FrameGraph::RenderPassBuilder& builder)
void DemoPass::Setup(FrameGraph& graph, RenderPassBuilder& builder)
{
AttachmentDesc surface{};
surface.FromTexture(graph.mSurface);
auto edge = graph.CreateTextureBuild()
.Import(FrameGraph::NameSurface, surface)
.Edge();
AttachmentDesc surface{ graph.mSurface };
builder.Name("MiniPass")
.Type(RenderPassNodeType::Scene, RenderPassNodeFlag::Output)
.Write(edge, ResourceState::COLOR_ATTACHMENT);
.Write(surface, ResourceState::COLOR_ATTACHMENT);
}
void DemoPass::Execute(FrameGraph& graph, RenderPassContext& ctx)
{

View File

@ -173,17 +173,15 @@ namespace pmr {
UNIQUER_INLINE_STATIC(StringEntryMemoryManager, stringEntryMemoryManager, "pmr::name::stringEntryMemoryManager")
uint32_t flag3_memory29;
public:
friend class std::hash<Name>;
Name()noexcept : flag3_memory29(0) {};
Name(std::string view) noexcept : flag3_memory29(MakeInterned(view)) {};
Name(std::string_view view) noexcept : flag3_memory29(MakeInterned(view)) {};
template<size_t N>
Name(const char(&str)[N]) noexcept : Name(std::string_view(str)) {}
Name(const char* str)noexcept : Name(std::string_view(str)){};
auto operator<=>(const Name& other) const noexcept { return flag3_memory29 <=> other.flag3_memory29; };
constexpr auto operator<=>(const Name& other) const noexcept { return flag3_memory29 <=> other.flag3_memory29; };
uint32_t MakeInterned(std::string_view view);
uint32_t Hash() const{
return flag3_memory29;
}
operator uint32_t() const {
return flag3_memory29;
}
@ -212,14 +210,38 @@ namespace pmr {
return std::string(stringEntry->GetData(), stringEntry->GetSize());
}
};
class Tag {
private:
Name name;
int number;
public:
friend class std::hash<Tag>;
Tag(Name name, int number): name(name), number(number) {}
Tag(Name name): name(name), number(0) {}
Tag(): name(), number(0) {}
Name getName() const { return name; }
int getNumber() const { return number; }
constexpr auto operator<=>(const Tag& other) const noexcept = default;
};
}
namespace std {
template<>
struct hash<::pmr::Name>
{
uint32_t operator()(const ::pmr::Name& name) const noexcept
size_t operator()(const ::pmr::Name& name) const noexcept
{
return name.Hash();
return std::hash<int>{}(name.flag3_memory29);
}
};
template<>
struct hash<::pmr::Tag>
{
size_t operator()(const ::pmr::Tag& tag) const noexcept
{
size_t h1 = std::hash<int>{}((uint32_t)tag.name);
size_t h2 = std::hash<int>{}(tag.number);
return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
}
};
}

View File

@ -37,6 +37,10 @@ namespace vkn {
BufferCommand(const BufferUpload& cmd) : cmd(cmd){}
BufferCommand(const BufferCreator& cmd) : cmd(cmd) {}
};
struct ImageCreator {
VkImageCreateInfo imageInfo;
VkImage* image;
};
class BufferWorker : public ThreadWorker<BufferCommand, BufferWorker>{
public:
//pmr::vector<Buffer> mPool{BufferPool()};
@ -45,5 +49,6 @@ namespace vkn {
void Loop();
void UploadBuffer(const BufferUpload& elem);
void CreateBuffer(BufferCreator& elem);
void CreateImage(ImageCreator& elem);
};
};

View File

@ -18,7 +18,7 @@ namespace vkn {
using commandFn = std::function<void(CommandBuffer& cmd)>;
using api::TargetBufferFlags;
using api::ResourceBarrierDesc;
using api::TextureViewDesc;
using api::TextureViewKey;
using api::ImageViewPtr;
using api::ImagePtr;
using api::TextureDimension;

View File

@ -15,10 +15,10 @@ namespace vkn {
private:
VulkanWindow& window;
Backend backend;
table<Guid, MeshVAO> MeshTable;
table<Guid, VulkanPipeline> PipelineTable;
table<size_t, RenderPassInfo> RenderPassCache;
table<Name, RenderPassInfo> RenderPassNameCache;
table<Guid, MeshVAO> MeshTable;
table<Guid, VulkanPipeline> PipelineTable;
table<size_t, RenderPassInfo> RenderPassCache;
table<Name, RenderPassInfo> RenderPassNameCache;
table<FramebufferKey, VkFramebuffer> FramebufferCache;
public:
VulkanAPI();
@ -32,8 +32,8 @@ namespace vkn {
void LoadShader(Shader& shader, size_t passKey)override;
void CreateBuffer(BufferDesc& desc) override;
ImagePtr CreateTexture(TextureDesc desc)override;
ImageViewPtr CreateTextureView(TextureViewDesc desc)override;
void CreateTexture(TextureDesc& desc)override;
ImageViewPtr CreateTextureView(TextureViewKey desc)override;
void BeginFrame()override;
void EndFrame()override;

View File

@ -1,5 +1,6 @@
#include "type.h"
namespace vkn {
using api::TextureUsage;
using api::ResourceState;
using api::TextureBarrier;
using api::ShaderDescriptorType;
@ -16,7 +17,7 @@ namespace vkn {
VkImageLayout vkApiGetImageLayout(ResourceState layout);
VkImageMemoryBarrier vkApiGetTextureTransition(VkPipelineStageFlags& mSrcStage, VkPipelineStageFlags& mDstStage, const TextureBarrier& barrier);
VkImageAspectFlags vkApiGetImageAspectMask(VkFormat format, bool includeStencilBit);
VkImageUsageFlags vkApiGetImageUsageFlags(ResourceState startState);
VkImageUsageFlags vkApiGetImageUsageFlags(TextureUsage usage);
VkImageViewType vkApiGetImageViewType(TextureDimension dimension, uint32_t arraySize);
VkImageType vkApiGetImageType(TextureDimension dimension);
VkImageCreateFlags vkApiGetImageCreateFlag(TextureDimension dimension, uint32_t arraySize);

View File

@ -2,18 +2,24 @@
#include "render/editor_system.h"
#include "render/graph/frame_graph.h"
namespace vkn {
using api::TextureDesc;
using api::FrameGraph;
using api::RenderPassContext;
using api::RenderPassBuilder;
using api::RenderEditorContext;
class VulkanImguiEditor : public api::EditorSystem {
public:
void Initialize() override;
void Finalize() override;
void Render();
void OnBeginRenderFrame();
ImTextureID AddTexture(const TextureDesc& desc) override;
void Render(FrameGraph& graph, RenderEditorContext& ctx);
void OnBeginRenderFrame(FrameGraph& graph, uint32_t frame);
static VulkanImguiEditor* Ptr() {
return (VulkanImguiEditor*)api::EditorSystem::Ptr();
};
static void Setup(FrameGraph& graph, FrameGraph::RenderPassBuilder& builder);
static void Setup(FrameGraph& graph, RenderPassBuilder& builder);
static void Execute(FrameGraph&, RenderPassContext&);
};
}

View File

@ -32,12 +32,6 @@ namespace vkn {
VulkanSwapchain(Device& device, VkSurfaceKHR surface, VulkanWindowArgs& args);
void Aquire(VulkanContext& ctx);
void Present(VulkanContext& ctx);
int FrameCount() const {
return mFrames;
}
const pmr::vector<TextureDesc>& GetSurface() {
return mSurfaces;
}
};
class VULKAN_API VulkanWindow : public api::Window {
private:

View File

@ -90,4 +90,13 @@ namespace vkn {
if (elem.ppCpuData)
vmaMapMemory(vmaAllocator, *elem.pAllocation, elem.ppCpuData);
}
void BufferWorker::CreateImage(ImageCreator& elem)
{
// 创建图像并分配内存
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
VmaAllocation allocation;
VkResult result = vmaCreateImage(vmaAllocator, &elem.imageInfo, &allocCreateInfo, elem.image, &allocation, nullptr);
}
}

View File

@ -269,12 +269,8 @@ namespace vkn {
{
}
ImagePtr VulkanAPI::CreateTexture(TextureDesc desc)
void VulkanAPI::CreateTexture(TextureDesc& desc)
{
if (desc.image) {
return desc.image;
}
uint32_t depth = any(desc.dimension & TextureDimension::TEX_3D) ? 3 : 1;
VkImageCreateInfo imageCreateInfo = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = NULL,
@ -290,15 +286,16 @@ namespace vkn {
.arrayLayers = desc.arraySize,
.samples = vkApiGetSmpleCountFlag(desc.sampleCount),
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = vkApiGetImageUsageFlags(desc.state),
.usage = vkApiGetImageUsageFlags(desc.usage),
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = NULL,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED
.initialLayout = vkApiGetImageLayout(desc.state)
};
return ImagePtr();
ImageCreator imageCreator{ .imageInfo = imageCreateInfo ,.image = (VkImage*)&desc.image };
Backend::TransferWorker->CreateImage(imageCreator);
}
ImageViewPtr VulkanAPI::CreateTextureView(TextureViewDesc desc)
ImageViewPtr VulkanAPI::CreateTextureView(TextureViewKey desc)
{
VkImageViewCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
@ -332,8 +329,8 @@ namespace vkn {
{
VulkanContext& ctx = *(VulkanContext*)&context;
window.Aquire(ctx);
graph.mSurface = ctx.surface;
EventSystem::Ptr()->BeginRenderFrame.Invoke();
graph.Input(ctx.surface);
EventSystem::Ptr()->BeginRenderFrame.Invoke(graph, ctx.frame);
}
void VulkanAPI::EndFrame()
{
@ -361,7 +358,6 @@ namespace vkn {
}
void VulkanAPI::BeginRenderPass(RenderPassNode* node, FnEnterRenderPass callback)
{
RenderPassInfo* passInfo = GetRenderPassInfo(node->name, node->hash);
RenderPassKey config{};
FramebufferKey frameKey{.layers = 1};
VkClearValue clearValues[2 * MAX_SUPPORTED_RENDER_TARGET_COUNT + 1] = { 0 };
@ -369,22 +365,24 @@ namespace vkn {
for (auto& it : node->outEdges) {
if (it->IsAttachment()) {
auto& desc = it->CastTo<api::AttachmentDesc>();
config.colorFormat[i] = (VkFormat)TinyImageFormat_ToVkFormat(desc.colorFormat);
config.samples = vkApiGetSmpleCountFlag(desc.sampleCount);
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;
it.ResolveView(&graph);
desc.imageView = graph.ResolveTextureView(texture);
frameKey.imageViews[i] = (VkImageView)desc.imageView;
frameKey.height = desc.height;
frameKey.width = desc.width;
frameKey.height = texture.height;
frameKey.width = texture.width;
//clearValues[i] =
i++;
}
}
frameKey.attachmentCount = i;
RenderPassInfo* passInfo = GetRenderPassInfo(node->name, node->hash);
if (!passInfo) {
passInfo = GetRenderPassInfo(node->hash, config);
}

View File

@ -179,12 +179,12 @@ namespace vkn {
}
return result;
}
VkImageUsageFlags vkApiGetImageUsageFlags(ResourceState startState)
VkImageUsageFlags vkApiGetImageUsageFlags(TextureUsage usage)
{
VkImageUsageFlags usageFlags = 0;
if (any(startState & ResourceState::COLOR_ATTACHMENT))
if (any(usage & TextureUsage::COLOR_ATTACHMENT))
usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
else if (any(startState & ResourceState::DEPTH_ATTACHMENT))
else if (any(usage & TextureUsage::DEPTH_ATTACHMENT))
usageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
return usageFlags;
}
@ -223,7 +223,7 @@ namespace vkn {
if (any(dimension & TextureDimension::TEX_CUBE)) {
flag |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
}
if (arraySize > 0) {
if (arraySize > 1) {
flag |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR;
}
return flag;

View File

@ -8,6 +8,7 @@
#include "vkn/wrapper/queue.h"
#include "imgui/imgui_impl_vulkan.h"
#include "imgui/imgui_impl_sdl2.h"
#include "data/global.h"
#include "event/event_system.h"
#include "tinyimageformat/tinyimageformat_apis.h"
namespace vkn {
@ -88,7 +89,7 @@ namespace vkn {
Backend& backend = API->GetBackend();
Queue* pQueue = backend.GetDevice().GetQueue(Queue::RenderQueue);
VkDescriptorPool descriptorPool = CreateDescriptorPool(backend.GetDevice().Ptr());
VkRenderPass renderPass = CreateRenderPass(API->graph.mSurface.format, backend.GetDevice().Ptr());
VkRenderPass renderPass = CreateRenderPass(API->context.surface.format, backend.GetDevice().Ptr());
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance = backend.GetInstance().Ptr();
@ -98,7 +99,7 @@ namespace vkn {
init_info.Queue = pQueue->Ptr();
init_info.DescriptorPool = descriptorPool;
init_info.MinImageCount = 2;
init_info.ImageCount = window->Swapchain()->FrameCount();
init_info.ImageCount = API->context.frameCount;
init_info.RenderPass = renderPass;
init_info.PipelineCache = VK_NULL_HANDLE;
init_info.Subpass = 0;
@ -106,42 +107,69 @@ namespace vkn {
init_info.Allocator = VK_NULL_HANDLE;
ImGui_ImplVulkan_Init(&init_info);
API->SetRenderPassInfo(ImguiPassName, renderPass);
//gEngineConfig.IsRenderEditorSurface = true;
if (gEngineConfig.IsRenderEditorSurface) {
TextureDesc desc{};
desc.width = 200;
desc.height = 200;
desc.format = TinyImageFormat_FromVkFormat((TinyImageFormat_VkFormat)VK_FORMAT_B8G8R8A8_SRGB);
desc.state = ResourceState::UNDEFINED;
desc.sampleCount = SampleCount::SAMPLE_COUNT_1;
desc.arraySize = 1;
desc.mipLevel = 1;
desc.depth = 1;
desc.dimension = TextureDimension::TEX_2D;
desc.usage = TextureUsage::COLOR_ATTACHMENT;
for (uint32_t i = 0; i < API->context.frameCount; i++) {
API->graph.SetResourceTexture(desc, FrameGraph::NameEditorSurface, i);
}
}
EventSystem::Ptr()->BeginRenderFrame.Subscribe(&VulkanImguiEditor::OnBeginRenderFrame, this);
}
void VulkanImguiEditor::Finalize()
{
}
void VulkanImguiEditor::Render()
ImTextureID VulkanImguiEditor::AddTexture(const TextureDesc& desc)
{
// 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{};
}
void VulkanImguiEditor::Render(FrameGraph& graph, RenderEditorContext& ctx)
{
for (auto win : mWindows)
{
win->Draw();
win->Draw(graph, ctx);
}
}
void VulkanImguiEditor::OnBeginRenderFrame()
void VulkanImguiEditor::OnBeginRenderFrame(FrameGraph& graph, uint32_t frame)
{
VulkanAPI::Ptr()->graph.AddRenderPass<VulkanImguiEditor>();
graph.mIsRenderEditorSurface = gEngineConfig.IsRenderEditorSurface;
if (gEngineConfig.IsRenderEditorSurface) {
graph.mEditorSurface = graph.mSurface;
graph.mSurface = graph.ResourceTexture(FrameGraph::NameEditorSurface, frame);
}
graph.AddRenderPass<VulkanImguiEditor>();
}
void VulkanImguiEditor::Setup(FrameGraph& graph, FrameGraph::RenderPassBuilder& builder)
void VulkanImguiEditor::Setup(FrameGraph& graph, RenderPassBuilder& builder)
{
AttachmentDesc surface{};
surface.FromTexture(graph.mSurface);
auto edge = graph.CreateTextureBuild()
.Import(FrameGraph::NameSurface, surface)
.Edge();
AttachmentDesc surface{ gEngineConfig.IsRenderEditorSurface ? graph.mEditorSurface : graph.mSurface };
builder.Name(ImguiPassName)
.Type(RenderPassNodeType::Imgui, RenderPassNodeFlag::Output)
.Write(edge, ResourceState::COLOR_ATTACHMENT);
.Write(surface, ResourceState::COLOR_ATTACHMENT);
}
void VulkanImguiEditor::Execute(FrameGraph& graph, RenderPassContext& context)
{
graph.mSurface.state = ResourceState::PRESENT;
TextureDesc& surface = graph.mEditorSurface.image ? graph.mEditorSurface : graph.mSurface;
graph.TransitionState(surface, ResourceState::PRESENT);
ImGui_ImplVulkan_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
VulkanImguiEditor::Ptr()->Render();
RenderEditorContext editorContext{};
VulkanImguiEditor::Ptr()->Render(graph, editorContext);
ImGui::Render();
VulkanContext& ctx = *(VulkanContext*)context.parent;

View File

@ -23,7 +23,8 @@ namespace vkn {
args.height = mHeight;
mSwapchain = new (GlobalPool()) VulkanSwapchain(backend.GetDevice(), surface, args);
api->context.frameCount = args.frames;
api->graph.InitSurface(std::span<TextureDesc>{mSwapchain->mSurfaces.data(), args.frames});
api->context.surface = mSwapchain->mSurfaces[0];
api->graph.InitSurface(mSwapchain->mSurfaces.data(), mSwapchain->mSurfaces.size());
return true;
}
VulkanSwapchain::VulkanSwapchain(Device& device, VkSurfaceKHR surface, VulkanWindowArgs& args)

View File

@ -1,9 +1,17 @@
#include "editor/panel/asset_preview_panel.h"
#include "data/global.h"
#include <imgui.h>
namespace api {
void AssetPreviewPanel::DrawPanel() {
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));
}
}
}

View File

@ -2,7 +2,7 @@
#include <imgui.h>
namespace api {
void MenuBarPanel::DrawPanel()
void MenuBarPanel::DrawPanel(FrameGraph& graph, RenderEditorContext& context)
{
// 面板大小和位置
if (ImGui::BeginMenu("Tools")) {

View File

@ -8,11 +8,11 @@ namespace api {
AddPanel<MenuBarPanel>();
AddPanel<AssetPreviewPanel>();
}
void EditorMainWindow::Draw()
void EditorMainWindow::Draw(FrameGraph& graph, RenderEditorContext& context)
{
ImGui::Begin("MainWindow");
for (auto panel : mPanels) {
panel->DrawPanel();
panel->DrawPanel(graph, context);
}
ImGui::End();
}

View File

@ -27,8 +27,8 @@ void ZWorldModule::OnLoad(int argc, char** argv)
#ifdef WITH_EDITOR //绑定窗口交互
ImGui_ImplSDL2_InitForVulkan(window->GetPtr());
#endif
EventSystem::Ptr()->BeginRenderFrame.Subscribe(mInfo.name, []() {
API->graph.AddRenderPass<DemoPass>();
EventSystem::Ptr()->BeginRenderFrame.Subscribe(mInfo.name, [](FrameGraph& graph, uint32_t frame) {
graph.AddRenderPass<DemoPass>();
});
}
void ZWorldModule::Initialize()