framegraph 资源优化 & 支持imgui::image

This commit is contained in:
ouczbs 2024-12-20 10:29:52 +08:00
parent fef024d407
commit 44bf81dcfe
22 changed files with 425 additions and 158 deletions

View File

@ -0,0 +1,14 @@
#include "render/editor_system.h"
namespace api {
SINGLETON_DEFINE(EditorSystem)
EditorSystem::EditorSystem()
{
SINGLETON_PTR();
}
ImTextureID EditorSystem::AddTexture(FrameGraph& graph, TextureDesc& desc, TextureSampler key)
{
ImageViewPtr imageview = graph.ResolveTextureView(desc);
SamplerPtr sampler = graph.ResolveTextureSampler(key);
return AddTexture(imageview, sampler, desc.state);
}
}

View File

@ -1,15 +1,5 @@
#include "render/renderapi.h"
#include "render/module.h"
#ifdef WITH_EDITOR
#include "render/editor_system.h"
namespace api {
SINGLETON_DEFINE(EditorSystem)
EditorSystem::EditorSystem()
{
SINGLETON_PTR();
}
}
#endif
namespace api {
SINGLETON_DEFINE(RenderAPI)
IMPLEMENT_STATIC_MODULE(RENDER_API, RenderModule, render);

View File

@ -4,8 +4,14 @@
#include "module/module_manager.h"
#include <imgui.h>
namespace api {
class RenderEditorContext {
class EditorSystem;
struct RenderEditorContext {
EditorSystem* editor;
uint32_t frame;
uint32_t frameCount;
EditorSystem* operator->() {
return editor;
}
};
class EditorPanel {
public:
@ -40,7 +46,8 @@ namespace api {
mWindows.push_back(ptr);
return ptr;
}
virtual ImTextureID AddTexture(const TextureDesc& desc) = 0;
ImTextureID AddTexture(FrameGraph& graph, TextureDesc& desc, TextureSampler sampler);
virtual ImTextureID AddTexture(ImageViewPtr imageview, SamplerPtr sampler, ResourceState state) = 0;
};
}
#endif // WITH_EDITOR

View File

@ -6,8 +6,9 @@ namespace api {
class FrameGraph
{
public:
TextureDesc mSurface{};
table<Tag, TextureDesc> mTextureTagMap;
uint32_t mSurfaceID{0};
table<TextureSampler, void*> mTextureSamplerPool;
table<Tag, uint32_t> mTextureTagMap;
table<TextureKey, uint32_t> mTextureKeyMap;
std::vector<TextureDesc> mTexturePool;
table<TextureViewKey, ImageViewPtr> mTextureViewPool;
@ -17,8 +18,9 @@ namespace api {
inline static Name NameSurface{ "surface" };
#ifdef WITH_EDITOR
inline static Name NameEditorSurface{ "editor_surface" };
TextureDesc mEditorSurface{};
bool mIsRenderEditorSurface{false};
uint32_t mEditorSurfaceID{ 0 };
TextureDesc& GetEditorSurface() { return ResolveTexture(mEditorSurfaceID); }
#endif //
public:
template<typename T>
@ -26,23 +28,27 @@ namespace api {
FrameGraphNodePtr AddRenderPass(const RenderPassSetupFunction& setup, const RenderPassNodeExecuteFn& executor);
RenderPassBuilder CreateRenderPassBuild();
void InitSurface(TextureDesc* surfaces, uint32_t frames);
void Input(const TextureDesc& surfaces) { mSurface = surfaces; };
void Input(const TextureDesc& surfaces) { mSurfaceID = surfaces.id; };
void Setup();
void Compile();
void Execute(FRenderView& view);
void Clear();
void CullGraph();
void FillGraph();
TextureDesc& GetSurface() { return ResolveTexture(mSurfaceID); }
TextureDesc& GetRenderSurface();
void TransitionState(TextureDesc& desc, ResourceState state);
bool ResolveState(TextureDesc& desc, ResourceState& srcstart, ResourceState& dststate);
bool ResolveState(AttachmentDesc& desc, ResourceState& srcstart, ResourceState& dststate);
bool ResolveState(BufferDesc& desc, ResourceState& srcstart, ResourceState& dststate);
TextureDesc& ResolveTexture(TextureDesc& desc);
TextureDesc& ResolveTexture(uint32_t id);
TextureDesc ResourceTexture(Name name, int num);
ImageViewPtr ResolveTextureView(TextureDesc& desc);
ImageViewPtr ResolveTextureView(TextureViewKey key);
void* ResolveTextureSampler(TextureSampler sampler);
void ResourceTexture(TextureDesc& desc);
void SetResourceTexture(TextureDesc texture, Name name, int num = 0);
uint32_t GetTextureID(Name name, int num);
public:
void ExecutePresentPass(FRenderView& view);
void ExecuteRenderPass(RenderPassNode* node, FRenderView& view);

View File

@ -11,6 +11,8 @@ namespace api {
: graph(*graph) , node(node) {};
RenderPassBuilder& Name(pmr::Name name);
RenderPassBuilder& Type(RenderPassNodeType type,RenderPassNodeFlag flag = RenderPassNodeFlag::None);
RenderPassBuilder& Read(TextureDesc desc, ResourceState state, pmr::Name name = {});
RenderPassBuilder& Write(AttachmentDesc desc, ResourceState state, pmr::Name name = {});
RenderPassBuilder& Dependency(RenderPassNode* rely) { node->dependencies.push_back(rely); return *this;}
};
}

View File

@ -40,9 +40,8 @@ namespace api {
using Resource = std::variant<TextureDesc, BufferDesc, AttachmentDesc>;
Name name;
Resource res;
RenderPassNode* node;
FrameResource() noexcept = default;
FrameResource(Name name,const Resource& res, RenderPassNode* node) : name(name), res(res), node(node){};
FrameResource(Name name,const Resource& res) : name(name), res(res){};
template<typename T>
T& CastTo() {
return std::get<T>(res);
@ -56,8 +55,8 @@ namespace api {
bool IsBuffer() const {
return std::holds_alternative<BufferDesc>(res);
}
static FrameResource* Make(Name name, const Resource& res, RenderPassNode* node) {
return new(FramePool()) FrameResource(name, res, node);
static FrameResource* Make(Name name, const Resource& res) {
return new(FramePool()) FrameResource(name, res);
}
};
using FrameGraphEdgePtr = FrameResource*;

View File

@ -35,7 +35,7 @@ namespace api {
virtual void CreateBuffer(BufferDesc& desc) = 0;
virtual void CreateTexture(TextureDesc& desc) = 0;
virtual ImageViewPtr CreateTextureView(TextureViewKey desc) = 0;
virtual SamplerPtr CreateTextureSampler(TextureSampler sampler) = 0;
virtual void BeginFrame() = 0;
virtual void EndFrame() = 0;
virtual void RenderView(FRenderView& view);

View File

@ -119,6 +119,91 @@ namespace api {
VERTEX = 0x1,
FRAGMENT = 0x2,
};
//! Sampler Wrap mode
enum class SamplerWrapMode : uint8_t {
CLAMP_TO_EDGE, //!< clamp-to-edge. The edge of the texture extends to infinity.
REPEAT, //!< repeat. The texture infinitely repeats in the wrap direction.
MIRRORED_REPEAT, //!< mirrored-repeat. The texture infinitely repeats and mirrors in the wrap direction.
};
//! Sampler minification filter
enum class SamplerMinFilter : uint8_t {
// don't change the enums values
NEAREST = 0, //!< No filtering. Nearest neighbor is used.
LINEAR = 1, //!< Box filtering. Weighted average of 4 neighbors is used.
NEAREST_MIPMAP_NEAREST = 2, //!< Mip-mapping is activated. But no filtering occurs.
LINEAR_MIPMAP_NEAREST = 3, //!< Box filtering within a mip-map level.
NEAREST_MIPMAP_LINEAR = 4, //!< Mip-map levels are interpolated, but no other filtering occurs.
LINEAR_MIPMAP_LINEAR = 5 //!< Both interpolated Mip-mapping and linear filtering are used.
};
//! Sampler magnification filter
enum class SamplerMagFilter : uint8_t {
// don't change the enums values
NEAREST = 0, //!< No filtering. Nearest neighbor is used.
LINEAR = 1, //!< Box filtering. Weighted average of 4 neighbors is used.
};
//! Sampler compare mode
enum class SamplerCompareMode : uint8_t {
// don't change the enums values
NONE = 0,
COMPARE_TO_TEXTURE = 1
};
//! comparison function for the depth / stencil sampler
enum class SamplerCompareFunc : uint8_t {
// don't change the enums values
LE = 0, //!< Less or equal
GE, //!< Greater or equal
L, //!< Strictly less than
G, //!< Strictly greater than
E, //!< Equal
NE, //!< Not equal
A, //!< Always. Depth / stencil testing is deactivated.
N //!< Never. The depth / stencil test always fails.
};
using SamplerPtr = void*;
//! Sampler parameters
struct TextureSampler { // NOLINT
SamplerMagFilter filterMag : 1; //!< magnification filter (NEAREST)
SamplerMinFilter filterMin : 3; //!< minification filter (NEAREST)
SamplerWrapMode wrapS : 2; //!< s-coordinate wrap mode (CLAMP_TO_EDGE)
SamplerWrapMode wrapT : 2; //!< t-coordinate wrap mode (CLAMP_TO_EDGE)
SamplerWrapMode wrapR : 2; //!< r-coordinate wrap mode (CLAMP_TO_EDGE)
uint8_t anisotropyLog2 : 3; //!< anisotropy level (0)
SamplerCompareMode compareMode : 1; //!< sampler compare mode (NONE)
uint8_t padding0 : 2; //!< reserved. must be 0.
SamplerCompareFunc compareFunc : 3; //!< sampler comparison function (LE)
uint8_t padding1 : 5; //!< reserved. must be 0.
uint8_t padding2 : 8; //!< reserved. must be 0.
struct EqualTo {
bool operator()(TextureSampler lhs, TextureSampler rhs) const noexcept {
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
return *pLhs == *pRhs;
}
};
struct LessThan {
bool operator()(TextureSampler lhs, TextureSampler rhs) const noexcept {
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
return *pLhs == *pRhs;
}
};
private:
friend inline bool operator < (TextureSampler lhs, TextureSampler rhs) noexcept {
return TextureSampler::LessThan{}(lhs, rhs);
}
public:
friend inline bool operator== (TextureSampler lhs, TextureSampler rhs) noexcept {
return TextureSampler::EqualTo{}(lhs, rhs);
}
};
struct MaterialResource {
Name name;
bool isDirty;
@ -209,6 +294,16 @@ namespace api {
uint8_t layerCount;
uint8_t baseMipLevel;
uint8_t levelCount;
friend inline bool operator==(const TextureViewKey& k1, const TextureViewKey& k2) {
if (k1.image != k2.image) return false;
if (k1.format != k2.format) return false;
if (k1.dimension != k2.dimension) return false;
if (k1.baseArrayLayer != k2.baseArrayLayer) return false;
if (k1.layerCount != k2.layerCount) return false;
if (k1.baseMipLevel != k2.baseMipLevel) return false;
if (k1.levelCount != k2.levelCount) return false;
return true;
}
};
struct TextureKey {
uint32_t id;
@ -220,6 +315,17 @@ namespace api {
TextureDimension dimension;
uint8_t mipLevel;
uint8_t arraySize;
friend inline bool operator==(const TextureKey& k1, const TextureKey& k2) {
if (k1.format != k2.format) return false;
if (k1.dimension != k2.dimension) return false;
if (k1.width != k2.width) return false;
if (k1.height != k2.height) return false;
if (k1.arraySize != k2.arraySize) return false;
if (k1.mipLevel != k2.mipLevel) return false;
if (k1.sampleCount != k2.sampleCount) return false;
if (k1.depth != k2.depth) return false;
return true;
}
};
struct TextureDesc : TextureKey {
ImagePtr image;
@ -303,27 +409,6 @@ namespace api {
barrier.mTexture = texture;
return barrier;
}
inline bool operator==(const TextureViewKey& k1, const TextureViewKey& k2) {
if (k1.image != k2.image) return false;
if (k1.format != k2.format) return false;
if (k1.dimension != k2.dimension) return false;
if (k1.baseArrayLayer != k2.baseArrayLayer) return false;
if (k1.layerCount != k2.layerCount) return false;
if (k1.baseMipLevel != k2.baseMipLevel) return false;
if (k1.levelCount != k2.levelCount) return false;
return true;
}
inline bool operator==(const TextureKey& k1, const TextureKey& k2) {
if (k1.format != k2.format) return false;
if (k1.dimension != k2.dimension) return false;
if (k1.width != k2.width) return false;
if (k1.height != k2.height) return false;
if (k1.arraySize != k2.arraySize) return false;
if (k1.mipLevel != k2.mipLevel) return false;
if (k1.sampleCount != k2.sampleCount) return false;
if (k1.depth != k2.depth) return false;
return true;
}
}
#include "meta/hash.h"
namespace std {
@ -335,7 +420,7 @@ namespace std {
return meta::MurmurHashFn(key);
}
};
template<>
template<>
struct hash<api::TextureKey>
{
size_t operator()(const api::TextureKey& key) const noexcept
@ -343,4 +428,12 @@ namespace std {
return meta::MurmurHashFn(key);
}
};
template<>
struct hash<api::TextureSampler>
{
size_t operator()(const api::TextureSampler& key) const noexcept
{
return std::hash<int>{}(*(int*)&key);
}
};
}

View File

@ -17,7 +17,8 @@ namespace api {
}
void FrameGraph::InitSurface(TextureDesc* surfaces, uint32_t frames)
{
mTexturePool.reserve(frames);
mTexturePool.reserve(frames + 1);
mTexturePool.push_back(TextureDesc{});
for (uint32_t i = 0; i < frames;i++) {
surfaces[i].id = mTexturePool.size() + 1;
mTexturePool.push_back(surfaces[i]);
@ -40,10 +41,8 @@ namespace api {
void FrameGraph::CullGraph()
{
pmr::vector<RenderPassNode*> outputNodes{FramePool()};
std::stack<RenderPassNode*> stack;
for (auto& node : mNodes) {
if (node->IsOutput()) {
stack.push(node.node);
outputNodes.push_back(node.node);
if ((!mLastOutputNode || node->type > mLastOutputNode->type)) {
mLastOutputNode = node.node;
@ -56,23 +55,6 @@ namespace api {
}
}
}
while (!stack.empty()) {
RenderPassNode* node = stack.top();
stack.pop();
if (node->isActive) {
continue;
}
node->isActive = true;
for (auto& edge : node->inEdges) {
if (edge->node && !edge->node->isActive) {
stack.push(edge->node);
}
}
}
auto end = std::remove_if(mNodes.begin(), mNodes.end(), [this](FrameGraphNodePtr& node) {
return !node->isActive;
});
mNodes.erase(end, mNodes.end());
if (outputNodes.size() > 1) {
std::sort(outputNodes.begin(), outputNodes.end(), [](RenderPassNode* a, RenderPassNode* b) {
if (a->type != b->type) {
@ -84,20 +66,43 @@ namespace api {
outputNodes[i]->dependencies.push_back(outputNodes[i - 1]);
}
}
//todo 需要考虑拓扑排序
std::stack<RenderPassNode*> stack;
stack.push(mLastOutputNode);
while (!stack.empty()) {
RenderPassNode* node = stack.top();
stack.pop();
if (node->isActive) {
continue;
}
node->isActive = true;
for (auto& rely : node->dependencies) {
if (!rely->isActive) {
stack.push(rely);
}
}
}
auto end = std::remove_if(mNodes.begin(), mNodes.end(), [this](FrameGraphNodePtr& node) {
return !node->isActive;
});
mNodes.erase(end, mNodes.end());
}
void FrameGraph::FillGraph()
{
std::pmr::unordered_set<RenderPassNode*> seenNodes{FramePool()};
pmr::vector<RenderPassNode*> result{ FramePool() };
for (auto& node : mNodes) {
if (!node->dependencies.empty()) {
seenNodes.insert(node->dependencies[0]);
}
for (auto& edge : node->inEdges) {
RenderPassNode* srcNode = edge->node;
if (srcNode && seenNodes.insert(srcNode).second) {
node->dependencies.push_back(srcNode);
bool isChange = false;
for (auto& rely : node->dependencies) {
bool isInsert = seenNodes.insert(rely).second;
isChange = isChange || !isInsert;
if (isInsert) {
result.push_back(rely);
}
}
if(isChange)
node->dependencies = result;
result.clear();
seenNodes.clear();
}
if (mLastOutputNode) {
@ -105,6 +110,14 @@ namespace api {
mLastOutputNode->flag |= RenderPassNodeFlag::LastOutput;
}
}
TextureDesc& FrameGraph::GetRenderSurface()
{
#ifdef WITH_EDITOR
return ResolveTexture(mIsRenderEditorSurface ? mEditorSurfaceID: mSurfaceID);
#else
return ResolveTexture(mSurfaceID);
#endif // WITH_EDITOR
}
void FrameGraph::Execute(FRenderView& view)
{
for (auto& node : mNodes) {
@ -141,13 +154,8 @@ namespace api {
}
void FrameGraph::ExecutePresentPass(FRenderView& view)
{
#ifdef WITH_EDITOR
TextureDesc& surface = ResolveTexture(mIsRenderEditorSurface ? mEditorSurface : mSurface);
#else
TextureDesc& surface = ResolveTexture(mSurface);
#endif // WITH_EDITOR
TextureDesc& surface = GetRenderSurface();
if (surface.state == ResourceState::PRESENT) {
surface.state = ResourceState::UNDEFINED;
return;
}
TextureBarrier barrier{};
@ -159,7 +167,6 @@ namespace api {
desc.textureBarriersCount = 1;
desc.pTextureBarriers = &barrier;
view.context->ExecuteSurfaceBarriers(desc);
surface.state = ResourceState::UNDEFINED;
}
void FrameGraph::ExecuteComputePass(RenderPassNode* node, FRenderView& view)
{
@ -204,32 +211,17 @@ namespace api {
}
void FrameGraph::TransitionState(TextureDesc& desc, ResourceState state)
{
TextureDesc& texture = ResolveTexture(desc);
TextureDesc& texture = ResolveTexture(desc.id);
desc.state = state;
texture.state = state;
if (texture.id == mSurface.id) {
mSurface.state = state;
}
#ifdef WITH_EDITOR
else if (texture.id == mEditorSurface.id) {
mEditorSurface.state = state;
}
#endif // WITH_EDITOR
}
bool FrameGraph::ResolveState(TextureDesc& desc, ResourceState& srcstart, ResourceState& dststate)
{
TextureDesc& texture = ResolveTexture(desc);
TextureDesc& texture = ResolveTexture(desc.id);
srcstart = texture.state;
dststate = desc.state;
texture.state = dststate;
if (texture.id == mSurface.id) {
mSurface.state = dststate;
}
#ifdef WITH_EDITOR
else if (texture.id == mEditorSurface.id) {
mEditorSurface.state = dststate;
}
#endif // WITH_EDITOR
desc.image = texture.image;
return srcstart == dststate;
}
bool FrameGraph::ResolveState(AttachmentDesc& desc, ResourceState& srcstart, ResourceState& dststate)
@ -240,12 +232,12 @@ namespace api {
{
return true;
}
TextureDesc& FrameGraph::ResolveTexture(TextureDesc& desc)
TextureDesc& FrameGraph::ResolveTexture(uint32_t id)
{
if (!desc.id || desc.id > mTexturePool.size()) {
return desc;
if (!id || id > mTexturePool.size()) {
return mTexturePool[0];//empty
}
TextureDesc& texture = mTexturePool[desc.id - 1];
TextureDesc& texture = mTexturePool[id - 1];
if (!texture.image) {
RenderAPI::Ptr()->CreateTexture(texture);
}
@ -254,7 +246,8 @@ namespace api {
ImageViewPtr FrameGraph::ResolveTextureView(TextureDesc& desc)
{
if (!desc.image) {
desc = ResolveTexture(desc);
TextureDesc& texture = ResolveTexture(desc.id);
desc.image = texture.image;
}
return ResolveTextureView(desc.ToTextureView());
}
@ -268,14 +261,22 @@ namespace api {
mTextureViewPool.emplace(key, view);
return view;
}
void* FrameGraph::ResolveTextureSampler(TextureSampler sampler)
{
auto iter = mTextureSamplerPool.find(sampler);
if (iter != mTextureSamplerPool.end()) {
return iter->second;
}
return RenderAPI::Ptr()->CreateTextureSampler(sampler);
}
TextureDesc FrameGraph::ResourceTexture(Name name, int num)
{
Tag tag(name, num);
auto it = mTextureTagMap.find(tag);
if (it != mTextureTagMap.end()) {
return it->second;
return ResolveTexture(it->second);
}
return TextureDesc{};
return mTexturePool[0];
}
void FrameGraph::ResourceTexture(TextureDesc& desc)
{
@ -289,17 +290,28 @@ namespace api {
mTexturePool.push_back(desc);
}
}
uint32_t FrameGraph::GetTextureID(Name name, int num)
{
Tag tag(name, num);
auto it = mTextureTagMap.find(tag);
if (it != mTextureTagMap.end()) {
return it->second;
}
return 0;
}
void FrameGraph::SetResourceTexture(TextureDesc desc, Name name, int num)
{
if (!desc.id) {
Tag tag(name, num);
auto it = mTextureTagMap.find(tag);
if (it != mTextureTagMap.end()) {
//todo: destroy texture
desc.id = it->second;
mTexturePool[desc.id - 1] = desc;
}
else {
desc.id = mTexturePool.size() + 1;
mTexturePool.push_back(desc);
mTextureTagMap[tag] = desc.id;
}
Tag tag(name, num);
//auto it = mTextureTagMap.find(tag);
//if (it != mTextureTagMap.end()) {
//todo: destroy texture
//}
mTextureTagMap[tag] = desc;
}
}

View File

@ -13,10 +13,18 @@ namespace api {
return *this;
}
RenderPassBuilder& RenderPassBuilder::Read(TextureDesc desc, ResourceState state, pmr::Name name)
{
desc.state = state;
FrameGraphEdgePtr edge = FrameResource::Make(name, desc);
node->inEdges.push_back(edge);
return *this;
}
RenderPassBuilder& RenderPassBuilder::Write(AttachmentDesc desc, ResourceState state, pmr::Name name)
{
desc.texture.state = state;
FrameGraphEdgePtr edge = FrameResource::Make(name, desc, node.node);
FrameGraphEdgePtr edge = FrameResource::Make(name, desc);
node->outEdges.push_back(edge);
return *this;
}

View File

@ -11,7 +11,7 @@ namespace api {
static RscHandle<Mesh> mesh;
void DemoPass::Setup(FrameGraph& graph, RenderPassBuilder& builder)
{
AttachmentDesc surface{ graph.mSurface };
AttachmentDesc surface{ graph.GetSurface()};
builder.Name("MiniPass")
.Type(RenderPassNodeType::Scene, RenderPassNodeFlag::Output)
.Write(surface, ResourceState::COLOR_ATTACHMENT);
@ -41,7 +41,7 @@ namespace api {
auto materialInstance = mesh->GetMaterialInstance();
materialInstance.SetClassResource(Name("uColor"), Vector4{1,0,0,1});
}
auto& surface = graph.mSurface;
auto& surface = graph.GetSurface();
ctx->SetViewport(0.0f, 0.0f,(float)surface.width,(float)surface.height, 0.f, 1.f);
ctx->SetScissor(0, 0, surface.width, surface.height);
RenderAPI::Ptr()->DrawStaticMesh(*mesh);

View File

@ -23,6 +23,8 @@ namespace vkn {
using api::ImagePtr;
using api::TextureDimension;
using api::SampleCount;
using api::TextureSampler;
using api::SamplerPtr;
using api::ResourceState;
using api::TextureDesc;
using api::BufferDesc;
@ -78,6 +80,17 @@ namespace vkn {
uint32_t width;
uint32_t height;
uint32_t layers;
friend inline bool operator==(const FramebufferKey& k1, const FramebufferKey& k2) {
if (k1.pass != k2.pass) return false;
if (k1.attachmentCount != k2.attachmentCount) return false;
for (int i = 0; i < k1.attachmentCount; i++) {
if (k1.imageViews[i] != k2.imageViews[i]) return false;
}
if (k1.height != k2.height) return false;
if (k1.width != k2.width) return false;
if (k1.layers != k2.layers) return false;
return true;
}
};
// Equivalent to VkVertexInputAttributeDescription but half as big.
struct VertexInputAttributeDescription {
@ -121,17 +134,6 @@ namespace vkn {
uint32_t descCount = 0;
bool inUse = false;
};
inline bool operator==(const FramebufferKey& k1, const FramebufferKey& k2) {
if (k1.pass != k2.pass) return false;
if (k1.attachmentCount != k2.attachmentCount) return false;
for (int i = 0; i < k1.attachmentCount; i++) {
if (k1.imageViews[i] != k2.imageViews[i]) return false;
}
if (k1.height != k2.height) return false;
if (k1.width != k2.width) return false;
if (k1.layers != k2.layers) return false;
return true;
}
}
namespace std {
template<>

View File

@ -2,6 +2,11 @@
#include "vulkan_context.h"
#include "asset/res/guid.h"
#include "backend.h"
#ifdef API_DEBUG
#define gLogSemaphore(...) //zlog::info(__VA_ARGS__)
#else
#define gLogSemaphore(...)
#endif
namespace vkn {
class VulkanWindow;
using api::Guid;
@ -34,7 +39,7 @@ namespace vkn {
void CreateBuffer(BufferDesc& desc) override;
void CreateTexture(TextureDesc& desc)override;
ImageViewPtr CreateTextureView(TextureViewKey desc)override;
SamplerPtr CreateTextureSampler(TextureSampler sampler) override;
void BeginFrame()override;
void EndFrame()override;
void BeginRenderPass(RenderPassNode* node, FnEnterRenderPass callback) override;

View File

@ -26,4 +26,5 @@ namespace vkn {
VkDescriptorType vkApiGetDescriptorType(ShaderDescriptorType type);
VkShaderStageFlags vkApiGetShaderStageFlags(ShaderStage stage);
VkBufferUsageFlagBits vkApiGetBufferUsage(BufferUsage usage);
VkSamplerCreateInfo vkApiGetSamplerCreateInfo(TextureSampler sampler);
}

View File

@ -1,8 +1,8 @@
#pragma once
#include "render/editor_system.h"
#include "render/graph/frame_graph.h"
#include "vkn/vulkan_api.h"
namespace vkn {
using api::TextureDesc;
using api::FrameGraph;
using api::RenderPassContext;
using api::RenderPassBuilder;
@ -12,7 +12,7 @@ namespace vkn {
void Initialize() override;
void Finalize() override;
ImTextureID AddTexture(const TextureDesc& desc) override;
ImTextureID AddTexture(ImageViewPtr imageview, SamplerPtr sampler, ResourceState state) override;
void Render(FrameGraph& graph, RenderEditorContext& ctx);
void OnBeginRenderFrame(FrameGraph& graph, uint32_t frame);

View File

@ -325,6 +325,13 @@ namespace vkn {
vkCreateImageView(backend.GetDevice().Ptr(), &createInfo, nullptr, &imageView);
return (ImageViewPtr)imageView;
}
SamplerPtr VulkanAPI::CreateTextureSampler(TextureSampler key)
{
VkSamplerCreateInfo samplerInfo = vkApiGetSamplerCreateInfo(key);
VkSampler sampler;
vkCreateSampler(backend.GetDevice().Ptr(), &samplerInfo, nullptr, &sampler);
return sampler;
}
void VulkanAPI::BeginFrame()
{
VulkanContext& ctx = *(VulkanContext*)&context;
@ -435,13 +442,13 @@ namespace vkn {
if (node->IsFirstInput()) {
waitDstStageMasks[semaphoreCount] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
waitSemaphores[semaphoreCount++] = ctx.surfaceSemaphore;
//zlog::info("-----wait {:#x}", (uintptr_t)ctx.surfaceSemaphore);
gLogSemaphore("-----wait {:#x}", (uintptr_t)ctx.surfaceSemaphore);
}
for (auto& it : node->dependencies) {
RenderPassInfo* inputInfo = GetRenderPassInfo(it->name ,it->hash);
waitDstStageMasks[semaphoreCount] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
waitSemaphores[semaphoreCount++] = inputInfo->semaphores[context.frame];
//zlog::info("-----wait {:#x}", (uintptr_t)inputInfo->semaphores[context.frame]);
gLogSemaphore("-----wait {:#x}", (uintptr_t)inputInfo->semaphores[context.frame]);
}
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
@ -455,11 +462,12 @@ namespace vkn {
VkFence fence = nullptr;
if (node->IsLastOutput()) {
ctx.graphSemaphore = passInfo->semaphores[context.frame];
if (graph.mSurface.state == ResourceState::PRESENT) {
TextureDesc& surface = graph.GetRenderSurface();
if (surface.state == ResourceState::PRESENT) {
fence = ctx.surfaceFence;
}
}
//zlog::info("+++++sign {:#x}", (uintptr_t)passInfo->semaphores[context.frame]);
gLogSemaphore("+++++sign {:#x}", (uintptr_t)passInfo->semaphores[context.frame]);
vkQueueSubmit(Backend::RenderWorker->GetQueue().Ptr(), 1, &submitInfo, fence);
}
RenderPassInfo* VulkanAPI::GetRenderPassInfo(Name name, size_t hash) {

View File

@ -184,8 +184,10 @@ namespace vkn {
VkImageUsageFlags usageFlags = 0;
if (any(usage & TextureUsage::COLOR_ATTACHMENT))
usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
else if (any(usage & TextureUsage::DEPTH_ATTACHMENT))
if (any(usage & TextureUsage::DEPTH_ATTACHMENT))
usageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
if(any(usage & TextureUsage::SAMPLEABLE))
usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
return usageFlags;
}
VkImageViewType vkApiGetImageViewType(TextureDimension dimension, uint32_t arraySize)
@ -267,4 +269,115 @@ namespace vkn {
}
return {};
}
using api::SamplerWrapMode;
using api::SamplerMinFilter;
using api::SamplerMagFilter;
using api::SamplerCompareMode;
using api::SamplerCompareFunc;
constexpr inline VkSamplerAddressMode getWrapMode(SamplerWrapMode mode) noexcept {
switch (mode) {
case SamplerWrapMode::REPEAT:
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
case SamplerWrapMode::CLAMP_TO_EDGE:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
case SamplerWrapMode::MIRRORED_REPEAT:
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
}
}
constexpr inline VkFilter getFilter(SamplerMinFilter filter) noexcept {
switch (filter) {
case SamplerMinFilter::NEAREST:
return VK_FILTER_NEAREST;
case SamplerMinFilter::LINEAR:
return VK_FILTER_LINEAR;
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
return VK_FILTER_NEAREST;
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
return VK_FILTER_LINEAR;
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
return VK_FILTER_NEAREST;
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
return VK_FILTER_LINEAR;
}
}
constexpr inline VkFilter getFilter(SamplerMagFilter filter) noexcept {
switch (filter) {
case SamplerMagFilter::NEAREST:
return VK_FILTER_NEAREST;
case SamplerMagFilter::LINEAR:
return VK_FILTER_LINEAR;
}
}
constexpr inline VkSamplerMipmapMode getMipmapMode(SamplerMinFilter filter) noexcept {
switch (filter) {
case SamplerMinFilter::NEAREST:
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
case SamplerMinFilter::LINEAR:
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
return VK_SAMPLER_MIPMAP_MODE_NEAREST;
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
return VK_SAMPLER_MIPMAP_MODE_LINEAR;
}
}
constexpr inline float getMaxLod(SamplerMinFilter filter) noexcept {
switch (filter) {
case SamplerMinFilter::NEAREST:
case SamplerMinFilter::LINEAR:
// The Vulkan spec recommends a max LOD of 0.25 to "disable" mipmapping.
// See "Mapping of OpenGL to Vulkan filter modes" in the VK Spec.
return 0.25f;
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST:
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST:
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR:
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR:
return VK_LOD_CLAMP_NONE;
}
}
constexpr inline VkBool32 getCompareEnable(SamplerCompareMode mode) noexcept {
return mode == SamplerCompareMode::NONE ? VK_FALSE : VK_TRUE;
}
VkCompareOp getCompareOp(SamplerCompareFunc func) {
using Compare = SamplerCompareFunc;
switch (func) {
case Compare::LE: return VK_COMPARE_OP_LESS_OR_EQUAL;
case Compare::GE: return VK_COMPARE_OP_GREATER_OR_EQUAL;
case Compare::L: return VK_COMPARE_OP_LESS;
case Compare::G: return VK_COMPARE_OP_GREATER;
case Compare::E: return VK_COMPARE_OP_EQUAL;
case Compare::NE: return VK_COMPARE_OP_NOT_EQUAL;
case Compare::A: return VK_COMPARE_OP_ALWAYS;
case Compare::N: return VK_COMPARE_OP_NEVER;
}
}
VkSamplerCreateInfo vkApiGetSamplerCreateInfo(TextureSampler sampler)
{
VkSamplerCreateInfo samplerInfo{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = getFilter(sampler.filterMag),
.minFilter = getFilter(sampler.filterMin),
.mipmapMode = getMipmapMode(sampler.filterMin),
.addressModeU = getWrapMode(sampler.wrapS),
.addressModeV = getWrapMode(sampler.wrapT),
.addressModeW = getWrapMode(sampler.wrapR),
.anisotropyEnable = sampler.anisotropyLog2 == 0 ? 0u : 1u,
.maxAnisotropy = (float)(1u << sampler.anisotropyLog2),
.compareEnable = getCompareEnable(sampler.compareMode),
.compareOp = getCompareOp(sampler.compareFunc),
.minLod = 0.0f,
.maxLod = getMaxLod(sampler.filterMin),
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
.unnormalizedCoordinates = VK_FALSE
};
return samplerInfo;
}
}

View File

@ -83,8 +83,8 @@ namespace vkn {
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
//zlog::info("-----wait {:#x}", (uintptr_t)waitSemaphores[0]);
//zlog::info("+++++sign {:#x}", (uintptr_t)signalSemaphores[0]);
gLogSemaphore("-----wait {:#x}", (uintptr_t)waitSemaphores[0]);
gLogSemaphore("+++++sign {:#x}", (uintptr_t)signalSemaphores[0]);
vkQueueSubmit(queue, 1, &submitInfo, surfaceFence);
graphSemaphore = presentSemaphore;
}

View File

@ -1,6 +1,5 @@
#include "vkn/vulkan_imgui_editor.h"
#include "vkn/vulkan_window.h"
#include "vkn/vulkan_api.h"
#include "vkn/vulkan_api_help.h"
#include "vkn/backend.h"
#include "vkn/wrapper/device.h"
@ -110,8 +109,8 @@ namespace vkn {
//gEngineConfig.IsRenderEditorSurface = true;
if (gEngineConfig.IsRenderEditorSurface) {
TextureDesc desc{};
desc.width = 200;
desc.height = 200;
desc.width = 512;
desc.height = 512;
desc.format = TinyImageFormat_FromVkFormat((TinyImageFormat_VkFormat)VK_FORMAT_B8G8R8A8_SRGB);
desc.state = ResourceState::UNDEFINED;
desc.sampleCount = SampleCount::SAMPLE_COUNT_1;
@ -119,7 +118,7 @@ namespace vkn {
desc.mipLevel = 1;
desc.depth = 1;
desc.dimension = TextureDimension::TEX_2D;
desc.usage = TextureUsage::COLOR_ATTACHMENT;
desc.usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
for (uint32_t i = 0; i < API->context.frameCount; i++) {
API->graph.SetResourceTexture(desc, FrameGraph::NameEditorSurface, i);
}
@ -130,12 +129,10 @@ namespace vkn {
{
}
ImTextureID VulkanImguiEditor::AddTexture(const TextureDesc& desc)
ImTextureID VulkanImguiEditor::AddTexture(ImageViewPtr imageview, SamplerPtr sampler, ResourceState state)
{
// 2. 通过 ImGui_ImplVulkan_AddTexture 连接 Vulkan 纹理和 ImGui
//ImTextureID textureID = (ImTextureID)(intptr_t)textureImageView;
//ImGui_ImplVulkan_AddTexture(textureSampler, textureImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
return ImTextureID{};
VkDescriptorSet descriptorSet = ImGui_ImplVulkan_AddTexture((VkSampler)sampler, (VkImageView)imageview, vkApiGetImageLayout(state));
return reinterpret_cast<ImTextureID>(descriptorSet);
}
void VulkanImguiEditor::Render(FrameGraph& graph, RenderEditorContext& ctx)
{
@ -148,28 +145,31 @@ namespace vkn {
{
graph.mIsRenderEditorSurface = gEngineConfig.IsRenderEditorSurface;
if (gEngineConfig.IsRenderEditorSurface) {
graph.mEditorSurface = graph.mSurface;
graph.mSurface = graph.ResourceTexture(FrameGraph::NameEditorSurface, frame);
graph.mEditorSurfaceID = graph.mSurfaceID;
graph.mSurfaceID = graph.GetTextureID(FrameGraph::NameEditorSurface, frame);
}
graph.AddRenderPass<VulkanImguiEditor>();
}
void VulkanImguiEditor::Setup(FrameGraph& graph, RenderPassBuilder& builder)
{
AttachmentDesc surface{ gEngineConfig.IsRenderEditorSurface ? graph.mEditorSurface : graph.mSurface };
AttachmentDesc surface{ graph.GetRenderSurface() };
builder.Name(ImguiPassName)
.Type(RenderPassNodeType::Imgui, RenderPassNodeFlag::Output)
.Write(surface, ResourceState::COLOR_ATTACHMENT);
if (gEngineConfig.IsRenderEditorSurface) {
builder.Read(graph.GetSurface(), ResourceState::READ_ONLY);
}
}
void VulkanImguiEditor::Execute(FrameGraph& graph, RenderPassContext& context)
{
TextureDesc& surface = graph.mEditorSurface.image ? graph.mEditorSurface : graph.mSurface;
graph.TransitionState(surface, ResourceState::PRESENT);
graph.GetRenderSurface().state = ResourceState::PRESENT;
ImGui_ImplVulkan_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
RenderEditorContext editorContext{};
VulkanImguiEditor::Ptr()->Render(graph, editorContext);
VulkanImguiEditor* editor = VulkanImguiEditor::Ptr();
RenderEditorContext editorContext{.editor = editor, .frame = context->frame, .frameCount = context->frameCount };
editor->Render(graph, editorContext);
ImGui::Render();
VulkanContext& ctx = *(VulkanContext*)context.parent;

View File

@ -103,11 +103,12 @@ namespace vkn {
vkAcquireNextImageKHR(mDevice.Ptr(), mPtr, UINT64_MAX, surfaceSemaphore, VK_NULL_HANDLE, &ctx.presentFrame);
vkResetFences(mDevice.Ptr(), 1, &surfaceFence);
ctx.surface = mSurfaces[ctx.presentFrame];
//zlog::info("aquire------------:: {:#x}", (uintptr_t)surfaceSemaphore);
ctx.graphSemaphore = nullptr;
gLogSemaphore("aquire------------:: {:#x}", (uintptr_t)surfaceSemaphore);
}
void VulkanSwapchain::Present(VulkanContext& ctx)
{
//zlog::info("present+++++++++++:: {:#x}", (uintptr_t)ctx.presentSemaphore);
gLogSemaphore("present+++++++++++:: {:#x}", (uintptr_t)ctx.presentSemaphore);
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.pWaitSemaphores = &ctx.graphSemaphore;

View File

@ -2,16 +2,19 @@
#include "data/global.h"
#include <imgui.h>
namespace api {
TextureSampler sampler;
ImTextureID TextureIDList[10] = {};
void AssetPreviewPanel::DrawPanel(FrameGraph& graph, RenderEditorContext& context) {
static float my_float = 0.5f;
ImGui::Text("This is some useful text.");
ImGui::SliderFloat("float", &my_float, 0.0f, 1.0f);
if (gEngineConfig.IsRenderEditorSurface) {
TextureDesc& surface = graph.mSurface;
// 2. 通过 ImGui_ImplVulkan_AddTexture 连接 Vulkan 纹理和 ImGui
//ImTextureID textureID = (ImTextureID)(intptr_t)graph.ResolveTextureView(surface);
// 3. 在 ImGui 窗口中渲染 Vulkan 纹理
//ImGui::Image(textureID, ImVec2(surface.width, surface.height));
TextureDesc surface = graph.GetSurface();
if (!TextureIDList[context.frame]) {
TextureIDList[context.frame] = context->AddTexture(graph, surface, sampler);
}
// 每帧渲染时都可以通过 ImTextureID 使用
ImGui::Image(TextureIDList[context.frame], ImVec2(surface.width, surface.height));
}
}
}

View File

@ -21,6 +21,9 @@
#define RENDER_API_VAL 1
#include "renderapi_impl.inl"
#include "window_impl.inl"
#ifdef WITH_EDITOR
#include "editor_system_impl.inl"
#endif
#endif // !RENDER_API_VAL
#ifndef APP_API_VAL