framegraph support semaphore

This commit is contained in:
ouczbs 2024-12-12 22:20:56 +08:00
parent a362258a03
commit 0166774b26
37 changed files with 3843 additions and 105 deletions

View File

@ -1,4 +1,4 @@
add_requires("spdlog", "lemon", "libsdl", "vulkansdk","shaderc","spirv","spirv-cross")
add_requires("mimalloc", {configs = {shared = true, debug = true, copy = true}})
add_requires("imgui")
add_requires("imgui",{configs = {shared = true, debug = true, copy = true}})
includes("*/xmake.lua")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
// dear imgui: Platform Backend for SDL2
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// Issues:
// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
// [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
// [x] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
struct SDL_Window;
struct SDL_Renderer;
struct _SDL_GameController;
typedef union SDL_Event SDL_Event;
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOther(SDL_Window* window);
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
// Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this.
// When using manual mode, caller is responsible for opening/closing gamepad.
enum ImGui_ImplSDL2_GamepadMode { ImGui_ImplSDL2_GamepadMode_AutoFirst, ImGui_ImplSDL2_GamepadMode_AutoAll, ImGui_ImplSDL2_GamepadMode_Manual };
IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = NULL, int manual_gamepads_count = -1);
#endif // #ifndef IMGUI_DISABLE

View File

@ -1,5 +1,15 @@
#include "render/renderapi.h"
#include "render/module.h"
#ifdef WITH_EDITOR
#include "render/imgui_system.h"
namespace api {
SINGLETON_DEFINE(ImguiSystem)
ImguiSystem::ImguiSystem()
{
SINGLETON_PTR();
}
}
#endif
namespace api {
SINGLETON_DEFINE(RenderAPI)
IMPLEMENT_STATIC_MODULE(RENDER_API, RenderModule, render);
@ -12,10 +22,12 @@ namespace api {
}
void RenderAPI::Render()
{
graph.mSurface = context.surface;
for (auto view : context.views) {
RenderView(view);
}
#ifdef WITH_EDITOR
//ImguiSystem::Ptr()->Render();
#endif
}
RenderAPI::RenderAPI(RenderContext* ctx) : context(*ctx)
{

View File

@ -22,7 +22,7 @@ namespace api {
FrameGraphNodePtr AddPresent(const FrameGraphEdgePtr& edge);
using TextureSetupFunction = std::function<void(FrameGraph&, class TextureBuilder&)>;
FrameGraphEdgePtr CreateTexture(const TextureSetupFunction& setup);
void InitSurface(const pmr::vector<TextureDesc>& surfaces);
void Compile();
void Execute(FRenderView& view);
void Clear();
@ -45,7 +45,7 @@ namespace api {
void ExecuteComputePass(RenderPassNode* node, FRenderView& view);
void ExecuteCopyPass(RenderPassNode* node, FRenderView& view);
void ExecuteResourceBarriers(RenderPassNode* node);
static void ExecuteResourceBarriers(RenderPassNode* node, RenderPassType type);
};
}
#include "frame_graph_builder.inl"

View File

@ -26,12 +26,7 @@ namespace api {
class RenderPass;
class RenderPassNode;
struct FrameGraphNodePtr {
enum NodeType : uint8_t {
Render,
Present,
Compute,
Copy
};
using NodeType = RenderPassType;
using GraphNodeRef = lemon::ListGraphBase::Node;
GraphNodeRef ref;
NodeType type{ NodeType::Render };

View File

@ -1,12 +1,21 @@
#pragma once
#ifdef WITH_EDITOR
#include "module/module_manager.h"
namespace api {
class RENDER_API ImguiSystem : public ISystem
{
SINGLETON_IMPL(ImguiSystem)
public:
ImguiSystem();
// 渲染开始和结束
// virtual void BeginFrame() = 0;
// virtual void EndFrame(void* command_buffer) = 0;
virtual void Render() {
BeginEditorRender();
EditorRender();
EndEditorRender();
}
virtual void BeginEditorRender() = 0;
virtual void EditorRender() = 0;
virtual void EndEditorRender() = 0;
};
}
#endif // WITH_EDITOR

View File

@ -1,3 +1,4 @@
#pragma once
#include "module/module_manager.h"
namespace api {
class RENDER_API RenderModule : public IStaticModule

View File

@ -8,6 +8,7 @@ namespace api {
struct RenderContext {
pmr::vector<FRenderView> views;
TextureDesc surface;
uint32_t frameCount{0};
uint32_t frame{ 0 };
uint32_t presentFrame{ 0 };
virtual void SetViewport(float x, float y, float width, float height, float min_depth, float max_depth) = 0;

View File

@ -39,7 +39,8 @@ namespace api {
virtual void BeginFrame() = 0;
virtual void EndFrame() = 0;
virtual void RenderView(FRenderView& view);
virtual void BeginRenderPass(RenderPassNode* node) = 0;
using FnEnterRenderPass = void(*)(RenderPassNode*);
virtual void BeginRenderPass(RenderPassNode* node, FnEnterRenderPass callback) = 0;
virtual void EndRenderPass(RenderPassNode* node) = 0;
virtual void ExecuteResourceBarriers(const ResourceBarrierDesc& desc) = 0;
void Render();

View File

@ -11,6 +11,12 @@ namespace api {
Vulkan,
D3D12
};
enum class RenderPassType : uint8_t {
Render,
Present,
Compute,
Copy
};
enum class BufferUsage {
STATIC = 0x01, //!< content modified once, used many times
DYNAMIC = 0x02, //!< content modified frequently, used many times
@ -84,6 +90,7 @@ namespace api {
};
enum class TextureDimension
{
TEX_NULL = 0,
TEX_1D = 0x01,
TEX_2D = 0x02,
TEX_3D = 0x04,
@ -176,6 +183,15 @@ namespace api {
static BufferDesc Make() {
return {};
}
};
struct TextureViewDesc {
ImagePtr image;
TinyImageFormat format : 16;
TextureDimension dimension : 8;
uint32_t baseArrayLayer : 8;
uint32_t layerCount : 8;
uint32_t baseMipLevel : 8;
uint32_t levelCount : 8;
};
struct TextureDesc {
ImagePtr image;
@ -188,17 +204,18 @@ namespace api {
uint32_t arraySize : 8;
TextureDimension dimension : 4;
uint32_t mipLevel : 4;
TextureViewDesc ToTextureView() const{
TextureViewDesc desc{};
desc.image = image;
desc.format = format;
desc.baseArrayLayer = 0;
desc.baseMipLevel = 0;
desc.layerCount = 1;
desc.levelCount = 1;
desc.dimension = dimension;
return desc;
}
};
struct TextureViewDesc {
ImagePtr image;
TinyImageFormat format : 16;
ResourceState state : 8;
TextureDimension dimension: 8;
uint32_t baseArrayLayer : 8;
uint32_t layerCount : 8;
uint32_t baseMipLevel : 8;
uint32_t levelCount : 8;
};
struct AttachmentDesc {
ImagePtr image;
ImageViewPtr imageView;
@ -213,13 +230,24 @@ namespace api {
image = desc.image;
return *this;
}
TextureDesc ToTexture() {
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;
}
};
struct TextureBarrier
{
@ -246,6 +274,7 @@ namespace api {
uint8_t mEndOnly : 1;
} BufferBarrier;
struct ResourceBarrierDesc {
RenderPassType type;
const BufferBarrier* pBufferBarriers;
uint32_t bufferBarriersCount;
const TextureBarrier* pTextureBarriers;

View File

@ -5,7 +5,6 @@ namespace api {
if (k1.image != k2.image) return false;
if (k1.format != k2.format) return false;
if (k1.dimension != k2.dimension) return false;
if (k1.state != k2.state) return false;
if (k1.baseArrayLayer != k2.baseArrayLayer) return false;
if (k1.layerCount != k2.layerCount) return false;
if (k1.baseMipLevel != k2.baseMipLevel) return false;
@ -49,6 +48,16 @@ namespace api {
setup(*this, builder);
return edge;
}
void FrameGraph::InitSurface(const pmr::vector<TextureDesc>& surfaces)
{
mSurface = surfaces[0];
RenderAPI* API = RenderAPI::Ptr();
for (auto& surface : surfaces) {
TextureViewDesc desc = surface.ToTextureView();
//ImageViewPtr view = API->CreateTextureView(desc);
//mResourceViewPool.emplace(desc, view);
}
}
void FrameGraph::Compile()
{
auto end = std::remove_if(mNodes.begin(), mNodes.end(), [this](FrameGraphNodePtr& node) {
@ -64,16 +73,16 @@ namespace api {
{
for (auto node : mNodes) {
switch (node.type) {
case FrameGraphNodePtr::Render:
case RenderPassType::Render:
ExecuteRenderPass(node.node, view);
break;
case FrameGraphNodePtr::Present:
case RenderPassType::Present:
ExecutePresentPass(node.node, view);
break;
case FrameGraphNodePtr::Compute:
case RenderPassType::Compute:
ExecuteComputePass(node.node, view);
break;
case FrameGraphNodePtr::Copy:
case RenderPassType::Copy:
ExecuteCopyPass(node.node, view);
break;
}
@ -86,15 +95,16 @@ namespace api {
}
void FrameGraph::ExecuteRenderPass(RenderPassNode* node, FRenderView& view)
{
ExecuteResourceBarriers(node);
RenderAPI::Ptr()->BeginRenderPass(node);
RenderAPI::Ptr()->BeginRenderPass(node, [](RenderPassNode* node) {
ExecuteResourceBarriers(node, RenderPassType::Render);
});
RenderPassContext context{view.context, node};
std::get<RenderPassExecuteFunction>(node->executor)(*this, context);
RenderAPI::Ptr()->EndRenderPass(node);
}
void FrameGraph::ExecutePresentPass(RenderPassNode* node, FRenderView& view)
{
ExecuteResourceBarriers(node);
ExecuteResourceBarriers(node, RenderPassType::Present);
}
void FrameGraph::ExecuteComputePass(RenderPassNode* node, FRenderView& view)
{
@ -106,12 +116,12 @@ namespace api {
CopyPassContext context{};
std::get<CopyPassExecuteFunction>(node->executor)(*this, context);
}
void FrameGraph::ExecuteResourceBarriers(RenderPassNode* node)
void FrameGraph::ExecuteResourceBarriers(RenderPassNode* node, RenderPassType type)
{
pmr::vector<BufferBarrier> bufferBarrier{FramePool()};
pmr::vector<TextureBarrier> textureBarrier{ FramePool() };
node->ForeachEdge([&, this](FrameResource* resource, FrameGraphEdgePtr edge) {
edge.Resolve(this);
node->ForeachEdge([&](FrameResource* resource, FrameGraphEdgePtr edge) {
edge.Resolve(&RenderAPI::Ptr()->graph);
if (!edge || edge.targetState == resource->sourceState) {
return;
}
@ -140,6 +150,7 @@ namespace api {
return;
}
ResourceBarrierDesc desc{};
desc.type = type;
desc.bufferBarriersCount = bufferBarrier.size();
desc.pBufferBarriers = bufferBarrier.data();
desc.textureBarriersCount = textureBarrier.size();

View File

@ -69,7 +69,6 @@ namespace api {
}
FrameGraph::TextureBuilder& FrameGraph::TextureBuilder::Import(pmr::Name name, AttachmentDesc desc, ResourceState state)
{
desc.image = nullptr;
edge->name = name;
edge->resource = desc;
edge.targetState = state;

View File

@ -33,16 +33,8 @@ namespace api {
}
if (resource->IsAttachment()) {
AttachmentDesc& attach = resource->CastTo<AttachmentDesc>();
TextureViewDesc view{};
view.image = attach.image;
view.format = attach.colorFormat;
view.state = targetState;
view.baseArrayLayer = 0;
view.baseMipLevel = 0;
view.layerCount = 1;
view.levelCount = 1;
view.dimension = attach.dimension;
attach.imageView = graph->ResolveTextureView(view);
TextureViewDesc desc = attach.ToTextureView();
attach.imageView = graph->ResolveTextureView(desc);
}
}
FrameGraphNodePtr::FrameGraphNodePtr(GraphNodeRef ref, NodeType type)

View File

@ -3,8 +3,8 @@ static_component("render","engine")
files = {"include/render/asset/*.h"}
})
add_includedirs("3rdparty", {public = true})
add_headerfiles("include/**.h", "include/**.inl")
add_files("src/**.cpp")
add_headerfiles("include/**.h", "include/**.inl", "3rdparty/imgui/*.h")
add_files("src/**.cpp", "3rdparty/imgui/*.cpp")
add_deps("asset", "zlib", "core")
add_syslinks("user32", {public = true})
add_packages("lemon", "libsdl","shaderc","spirv-cross", {public = true})

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,211 @@
// dear imgui: Renderer Backend for Vulkan
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [x] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions.
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
// You will use those if you want to use this rendering backend in your engine/app.
// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
// Read comments in imgui_impl_vulkan.h.
#pragma once
#ifndef IMGUI_DISABLE
#include "imgui.h" // IMGUI_IMPL_API
// [Configuration] in order to use a custom Vulkan function loader:
// (1) You'll need to disable default Vulkan function prototypes.
// We provide a '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' convenience configuration flag.
// In order to make sure this is visible from the imgui_impl_vulkan.cpp compilation unit:
// - Add '#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES' in your imconfig.h file
// - Or as a compilation flag in your build system
// - Or uncomment here (not recommended because you'd be modifying imgui sources!)
// - Do not simply add it in a .cpp file!
// (2) Call ImGui_ImplVulkan_LoadFunctions() before ImGui_ImplVulkan_Init() with your custom function.
// If you have no idea what this is, leave it alone!
//#define IMGUI_IMPL_VULKAN_NO_PROTOTYPES
// Convenience support for Volk
// (you can also technically use IMGUI_IMPL_VULKAN_NO_PROTOTYPES + wrap Volk via ImGui_ImplVulkan_LoadFunctions().)
//#define IMGUI_IMPL_VULKAN_USE_VOLK
#if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES) && !defined(VK_NO_PROTOTYPES)
#define VK_NO_PROTOTYPES
#endif
#if defined(VK_USE_PLATFORM_WIN32_KHR) && !defined(NOMINMAX)
#define NOMINMAX
#endif
// Vulkan includes
#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
#include <volk.h>
#else
#include <vulkan/vulkan.h>
#endif
#if defined(VK_VERSION_1_3) || defined(VK_KHR_dynamic_rendering)
#define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
#endif
// Initialization data, for ImGui_ImplVulkan_Init()
// [Please zero-clear before use!]
// - About descriptor pool:
// - A VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
// and must contain a pool size large enough to hold a small number of VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptors.
// - As an convenience, by setting DescriptorPoolSize > 0 the backend will create one for you.
// - Current version of the backend use 1 descriptor for the font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture().
// - It is expected that as early as Q1 2025 the backend will use a few more descriptors, so aim at 10 + number of desierd calls to ImGui_ImplVulkan_AddTexture().
// - About dynamic rendering:
// - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure.
struct ImGui_ImplVulkan_InitInfo
{
VkInstance Instance;
VkPhysicalDevice PhysicalDevice;
VkDevice Device;
uint32_t QueueFamily;
VkQueue Queue;
VkDescriptorPool DescriptorPool; // See requirements in note above; ignored if using DescriptorPoolSize > 0
VkRenderPass RenderPass; // Ignored if using dynamic rendering
uint32_t MinImageCount; // >= 2
uint32_t ImageCount; // >= MinImageCount
VkSampleCountFlagBits MSAASamples; // 0 defaults to VK_SAMPLE_COUNT_1_BIT
// (Optional)
VkPipelineCache PipelineCache;
uint32_t Subpass;
// (Optional) Set to create internal descriptor pool instead of using DescriptorPool
uint32_t DescriptorPoolSize;
// (Optional) Dynamic Rendering
// Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3.
bool UseDynamicRendering;
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo;
#endif
// (Optional) Allocation, Debugging
const VkAllocationCallbacks* Allocator;
void (*CheckVkResultFn)(VkResult err);
VkDeviceSize MinAllocationSize; // Minimum allocation size. Set to 1024*1024 to satisfy zealous best practices validation layer and waste a little memory.
};
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info);
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture();
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture();
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
// Register a texture (VkDescriptorSet == ImTextureID)
// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem
// Please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout);
IMGUI_IMPL_API void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set);
// Optional: load Vulkan functions with a custom function loader
// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES
IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = nullptr);
// [BETA] Selected render state data shared with callbacks.
// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplVulkan_RenderDrawData() call.
// (Please open an issue if you feel you need access to more data)
struct ImGui_ImplVulkan_RenderState
{
VkCommandBuffer CommandBuffer;
VkPipeline Pipeline;
VkPipelineLayout PipelineLayout;
};
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
//-------------------------------------------------------------------------
// You probably do NOT need to use or care about those functions.
// Those functions only exist because:
// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files.
// 2) the multi-viewport / platform window implementation needs them internally.
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
// but it is too much code to duplicate everywhere so we exceptionally expose them.
//
// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
//-------------------------------------------------------------------------
struct ImGui_ImplVulkanH_Frame;
struct ImGui_ImplVulkanH_Window;
// Helpers
IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator);
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
// Helper structure to hold the data needed by one rendering frame
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
// [Please zero-clear before use!]
struct ImGui_ImplVulkanH_Frame
{
VkCommandPool CommandPool;
VkCommandBuffer CommandBuffer;
VkFence Fence;
VkImage Backbuffer;
VkImageView BackbufferView;
VkFramebuffer Framebuffer;
};
struct ImGui_ImplVulkanH_FrameSemaphores
{
VkSemaphore ImageAcquiredSemaphore;
VkSemaphore RenderCompleteSemaphore;
};
// Helper structure to hold the data needed by one rendering context into one OS window
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
struct ImGui_ImplVulkanH_Window
{
int Width;
int Height;
VkSwapchainKHR Swapchain;
VkSurfaceKHR Surface;
VkSurfaceFormatKHR SurfaceFormat;
VkPresentModeKHR PresentMode;
VkRenderPass RenderPass;
bool UseDynamicRendering;
bool ClearEnable;
VkClearValue ClearValue;
uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
uint32_t SemaphoreCount; // Number of simultaneous in-flight frames + 1, to be able to use it in vkAcquireNextImageKHR
uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
ImGui_ImplVulkanH_Frame* Frames;
ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
ImGui_ImplVulkanH_Window()
{
memset((void*)this, 0, sizeof(*this));
PresentMode = (VkPresentModeKHR)~0; // Ensure we get an error if user doesn't set this.
ClearEnable = true;
}
};
#endif // #ifndef IMGUI_DISABLE

View File

@ -11,6 +11,7 @@
namespace vkn {
using pmr::Name;
using pmr::table;
using std::vector;
using std::string_view;
class CommandBuffer;
using voidFn = std::function<void()>;
@ -62,6 +63,14 @@ namespace vkn {
return meta::MurmurHashFn(this);
}
};
struct RenderPassInfo {
RenderPassKey config;
vector<VkSemaphore> semaphores;
vector<VkCommandBuffer> commands;
VkRenderPass Pass() {
return config.pass;
}
};
struct FramebufferKey {
VkRenderPass pass;
VkImageView imageViews[MAX_SUPPORTED_RENDER_TARGET_COUNT * 2 + 1];

View File

@ -10,13 +10,14 @@ namespace vkn {
using api::Material;
using api::MaterialInstance;
using api::RenderPassNode;
using api::RenderPassType;
class VULKAN_API VulkanAPI final : public api::RenderAPI{
private:
VulkanWindow& window;
Backend backend;
table<Guid, MeshVAO> MeshTable;
table<Guid, VulkanPipeline> PipelineTable;
table<size_t, RenderPassKey> RenderPassCache;
table<size_t, RenderPassInfo> RenderPassCache;
table<FramebufferKey, VkFramebuffer> FramebufferCache;
public:
VulkanAPI();
@ -35,12 +36,11 @@ namespace vkn {
void BeginFrame()override;
void EndFrame()override;
void BeginRenderPass(RenderPassNode* node) override;
void BeginRenderPass(RenderPassNode* node, FnEnterRenderPass callback) override;
void EndRenderPass(RenderPassNode* node) override;
void ExecuteResourceBarriers(const ResourceBarrierDesc& desc) override;
VkPipeline GetPipeline() { return nullptr; };
VkRenderPass GetRenderPass(size_t hash, RenderPassKey& config);
const RenderPassInfo& GetRenderPassInfo(size_t hash, const RenderPassKey& config = {});
Backend& GetBackend() {
return backend;
}

View File

@ -6,6 +6,8 @@ namespace vkn {
VkFence surfaceFence;
VkSemaphore surfaceSemaphore;
VkSemaphore presentSemaphore;
VkSemaphore graphSemaphore;
VkCommandBuffer surfaceCommand;
VkCommandBuffer command;
void SetScissor(uint32_t x, uint32_t y, uint32_t width, uint32_t height) override;
void SetViewport(float x, float y, float width, float height, float min_depth, float max_depth) override;

View File

@ -4,6 +4,8 @@ namespace vkn {
class VulkanImguiSystem : public api::ImguiSystem {
void Initialize() override;
void Finalize() override;
void BeginEditorRender() override;
void EditorRender() override;
void EndEditorRender() override;
};
}

View File

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

View File

@ -15,7 +15,6 @@ namespace vkn {
void EndRecord();
void CmdCopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
void Submit(VkQueue& queue,VkFence fence);
void BindVertexBuffer(VkBuffer buffer, uint32_t offset);
void BindIndexBuffers(VkBuffer buffer, uint32_t offset, VkIndexType type);
};

View File

@ -17,6 +17,7 @@ namespace vkn {
return mPtr;
};
CommandBuffer Pop();
void PopList(vector<VkCommandBuffer>& list, int size);
void Push(CommandBuffer& cmd);
};
}

View File

@ -27,6 +27,7 @@ namespace vkn {
VkFence PopFence();
void PushWaitFence(VkFence fence);
VkSemaphore CreateSemaphore();
void CreateSemaphores(vector<VkSemaphore>& list, int size);
VkShaderModule CreateShaderModule(const pmr::vector<char>& code);
VkShaderModule CreateShaderModule(const pmr::vector<uint32_t>& code);
};

View File

@ -1,11 +1,16 @@
#include "xmalloc_new_delete.h"
#include "vkn/module.h"
#include "vkn/vulkan_imgui.h"
#include "vkn/loader/vulkan_glsl_loader.h"
#include "pmr/frame_allocator.h"
using namespace vkn;
void VulkanModule::OnLoad(int argc, char** argv)
{
VulkanGlslLoader::Init();
#ifdef WITH_EDITOR
AddSystem<VulkanImguiSystem>();
#endif // WITH_EDITOR
}
void VulkanModule::OnUnload()

View File

@ -99,7 +99,7 @@ namespace vkn {
if (itPass == RenderPassCache.end()) {
return;
}
VkRenderPass renderpass = itPass->second.pass;
VkRenderPass renderpass = itPass->second.Pass();
pmr::vector<VkPipelineShaderStageCreateInfo> shaderStages;
std::map<VkShaderStageFlagBits, VkShaderModule> shaderModules;
auto& device = backend.GetDevice();
@ -343,6 +343,7 @@ namespace vkn {
VulkanContext& ctx = *(VulkanContext*)&context;
window.Aquire(ctx);
ctx.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
graph.mSurface = ctx.surface;
}
void VulkanAPI::EndFrame()
{
@ -366,9 +367,10 @@ namespace vkn {
if (dstStageMask == 0) {
dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
vkCmdPipelineBarrier(ctx.command, srcStageMask, dstStageMask, 0, 0, NULL, 0, NULL, imageBarriers.size(), imageBarriers.data());
VkCommandBuffer command = desc.type == RenderPassType::Present ? ctx.surfaceCommand : ctx.command;
vkCmdPipelineBarrier(command, srcStageMask, dstStageMask, 0, 0, NULL, 0, NULL, imageBarriers.size(), imageBarriers.data());
}
void VulkanAPI::BeginRenderPass(RenderPassNode* node)
void VulkanAPI::BeginRenderPass(RenderPassNode* node, FnEnterRenderPass callback)
{
RenderPassKey config{};
FramebufferKey frameKey{.layers = 1};
@ -394,14 +396,14 @@ namespace vkn {
}
frameKey.attachmentCount = i;
node->hash = config;
VkRenderPass pass = GetRenderPass(node->hash, config);
frameKey.pass = pass;
RenderPassInfo passInfo = GetRenderPassInfo(node->hash, config);
frameKey.pass = passInfo.Pass();
auto it = FramebufferCache.find(frameKey);
VkFramebuffer framebuffer = it->second;
if (it == FramebufferCache.end()) {
VkFramebufferCreateInfo framebufferInfo = {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.renderPass = pass,
.renderPass = frameKey.pass,
.attachmentCount = frameKey.attachmentCount,
.pAttachments = frameKey.imageViews,
.width = frameKey.width,
@ -418,24 +420,57 @@ namespace vkn {
VkRenderPassBeginInfo beginInfo = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.pNext = VK_NULL_HANDLE,
.renderPass = pass,
.renderPass = frameKey.pass,
.framebuffer = framebuffer,
.renderArea = renderAarea,
.clearValueCount = frameKey.attachmentCount,
.pClearValues = clearValues
};
VulkanContext& ctx = *(VulkanContext*)&context;
vkCmdBeginRenderPass(ctx.command, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
CommandBuffer cmd = passInfo.commands[context.frame];
ctx.command = cmd.Ptr();
cmd.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
if(callback) callback(node);
vkCmdBeginRenderPass(cmd.Ptr(), &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
void VulkanAPI::EndRenderPass(RenderPassNode* node)
{
VulkanContext& ctx = *(VulkanContext*)&context;
vkCmdEndRenderPass(ctx.command);
RenderPassInfo passInfo = GetRenderPassInfo(node->hash);
CommandBuffer cmd = passInfo.commands[context.frame];
vkCmdEndRenderPass(cmd.Ptr());
cmd.EndRecord();
VkSemaphore waitSemaphores[8];
VkPipelineStageFlags waitDstStageMasks[8];
uint32_t semaphoreCount = 0;
if (ctx.surfaceSemaphore) {
waitDstStageMasks[semaphoreCount] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
waitSemaphores[semaphoreCount++] = ctx.surfaceSemaphore;
ctx.surfaceSemaphore = nullptr;
}
for (auto& it : node->inEdges) {
RenderPassInfo inputInfo = GetRenderPassInfo(it->source->hash);
waitDstStageMasks[semaphoreCount] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
waitSemaphores[semaphoreCount++] = inputInfo.semaphores[context.frame];
}
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmd.Ptr();
submitInfo.pSignalSemaphores = &passInfo.semaphores[context.frame];
submitInfo.signalSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitDstStageMasks;
submitInfo.waitSemaphoreCount = semaphoreCount;
if (!ctx.graphSemaphore) {
ctx.graphSemaphore = passInfo.semaphores[context.frame];
}
vkQueueSubmit(Backend::RenderWorker->GetQueue().Ptr(), 1, &submitInfo, nullptr);
}
VkRenderPass VulkanAPI::GetRenderPass(size_t hash, RenderPassKey& config) {
const RenderPassInfo& VulkanAPI::GetRenderPassInfo(size_t hash, const RenderPassKey& config) {
auto it = RenderPassCache.find(hash);
if (it != RenderPassCache.end()) {
return it->second.pass;
return it->second;
}
// Set up some const aliases for terseness.
const VkAttachmentLoadOp kClear = VK_ATTACHMENT_LOAD_OP_CLEAR;
@ -599,8 +634,13 @@ namespace vkn {
};
}
renderPassInfo.attachmentCount = attachmentIndex;
VkResult error = vkCreateRenderPass(backend.GetDevice().Ptr(), &renderPassInfo, nullptr, &config.pass);
RenderPassCache.emplace(hash, config);
return config.pass;
VkRenderPass pass;
VkResult error = vkCreateRenderPass(backend.GetDevice().Ptr(), &renderPassInfo, nullptr, &pass);
RenderPassInfo info{ config};
info.config.pass = pass;
backend.GetDevice().CreateSemaphores(info.semaphores, context.frameCount);
Backend::RenderWorker->GetCommandPool().PopList(info.commands, context.frameCount);
RenderPassCache.emplace(hash, info);
return RenderPassCache[hash];
}
}

View File

@ -191,7 +191,7 @@ namespace vkn {
}
VkImageViewType vkApiGetImageViewType(TextureDimension dimension, uint32_t arraySize)
{
if (any(dimension & TextureDimension::TEX_1D)) {
if (dimension == TextureDimension::TEX_NULL || any(dimension & TextureDimension::TEX_1D)) {
return arraySize > 1 ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D;
}
if (any(dimension & TextureDimension::TEX_CUBE)) {
@ -203,7 +203,7 @@ namespace vkn {
if (any(dimension & TextureDimension::TEX_3D)) {
return VK_IMAGE_VIEW_TYPE_3D;
}
return VK_IMAGE_VIEW_TYPE_MAX_ENUM;
return arraySize > 1 ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D;
}
VkImageType vkApiGetImageType(TextureDimension dimension)
{

View File

@ -55,18 +55,18 @@ namespace vkn {
nullptr, //pNext
flag //flags
};
vkBeginCommandBuffer(command, &beginInfo);
vkBeginCommandBuffer(surfaceCommand, &beginInfo);
}
void VulkanContext::EndRecord(VkQueue queue)
{
vkEndCommandBuffer(command);
vkEndCommandBuffer(surfaceCommand);
VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; // 等待渲染阶段
VkSemaphore waitSemaphores[] = { surfaceSemaphore };
VkSemaphore waitSemaphores[] = { graphSemaphore };
VkSemaphore signalSemaphores[] = { presentSemaphore };// 渲染完成信号量
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &command;
submitInfo.pCommandBuffers = &surfaceCommand;
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
@ -75,5 +75,6 @@ namespace vkn {
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
vkQueueSubmit(queue, 1, &submitInfo, surfaceFence);
graphSemaphore = nullptr;
}
}

View File

@ -1,18 +1,22 @@
#include "vkn/vulkan_imgui.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"
#include "vkn/wrapper/instance.h"
#include "vkn/wrapper/queue.h"
#include "render/window.h"
#include "imgui.h"
#include "backends/imgui_impl_sdl2.h"
#include "backends/imgui_impl_vulkan.h"
#include "imgui/imgui_impl_vulkan.h"
#include "imgui/imgui_impl_sdl2.h"
#include "tinyimageformat/tinyimageformat_apis.h"
namespace vkn {
static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
void CreateDescriptorPool(VkDevice device, VkDescriptorPool& descriptorPool) {
static VkRenderPass g_RenderPass = VK_NULL_HANDLE;
static VkCommandPool g_CommandPool = VK_NULL_HANDLE;
static std::vector<VkCommandBuffer> g_CommandBuffers;
static std::vector<VkFramebuffer> g_FrameBuffers;
static std::vector<VkSemaphore> g_RenderFinishSemaphores;
VkDescriptorPool CreateDescriptorPool(VkDevice device) {
VkDescriptorPoolSize pool_sizes[] =
{
{ VK_DESCRIPTOR_TYPE_SAMPLER, 1000 },
@ -33,42 +37,198 @@ namespace vkn {
pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes);
pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes);
pool_info.pPoolSizes = pool_sizes;
VkResult err = vkCreateDescriptorPool(device, &pool_info, VK_NULL_HANDLE, &descriptorPool);
VkDescriptorPool descriptorPool;
vkCreateDescriptorPool(device, &pool_info, VK_NULL_HANDLE, &descriptorPool);
return descriptorPool;
}
void CreateRenderPass(VulkanAPI* API) {
RenderPassKey config{};
config.colorFormat[0] = (VkFormat)TinyImageFormat_ToVkFormat(API->context.surface.format);
config.samples = VK_SAMPLE_COUNT_1_BIT;
VkRenderPass CreateRenderPass(TinyImageFormat format, VkDevice device) {
VkAttachmentDescription colorAttachment = {};
colorAttachment.format = (VkFormat)TinyImageFormat_ToVkFormat(format);
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachmentRef = {};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
VkSubpassDependency dependency = {};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0; // or VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkRenderPassCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
info.attachmentCount = 1;
info.pAttachments = &colorAttachment;
info.subpassCount = 1;
info.pSubpasses = &subpass;
info.dependencyCount = 1;
info.pDependencies = &dependency;
VkRenderPass renderPass;
if (vkCreateRenderPass(device, &info, VK_NULL_HANDLE, &renderPass) != VK_SUCCESS)
throw std::runtime_error("Could not create Dear ImGui's render pass");
return renderPass;
}
void CreateFrameBuffer(VulkanAPI* API, VkRenderPass renderPass, const pmr::vector<TextureDesc>& surfaces) {
VkDevice device = API->GetBackend().GetDevice().Ptr();
g_FrameBuffers.resize(surfaces.size());
VkFramebuffer* framebuffer = g_FrameBuffers.data();
for (auto& surface : surfaces)
{
VkFramebufferCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.renderPass = renderPass;
info.pAttachments = (VkImageView*)API->graph.ResolveTextureView(surface.ToTextureView());
info.attachmentCount = 1;
info.width = surface.width;
info.height = surface.height;
info.layers = 1;
vkCreateFramebuffer(device, &info, VK_NULL_HANDLE, framebuffer++);
}
}
void CreateCommandPool(VkDevice device, int queueFamilyIndex, int frames) {
VkCommandPool commandPool;
// 创建一个专用的CommandPool
{
VkCommandPoolCreateInfo commandPoolCreateInfo = {};
commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
commandPoolCreateInfo.queueFamilyIndex = queueFamilyIndex;
commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
if (vkCreateCommandPool(device, &commandPoolCreateInfo, VK_NULL_HANDLE, &commandPool) != VK_SUCCESS)
throw std::runtime_error("Could not create graphics command pool");
}
// 创建专用的CommandBuffer
{
g_CommandBuffers.resize(frames);
VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandPool = commandPool;
allocInfo.commandBufferCount = frames;
if (vkAllocateCommandBuffers(device, &allocInfo, g_CommandBuffers.data()) != VK_SUCCESS)
throw std::runtime_error("failed to allocate command buffers!");
}
g_RenderFinishSemaphores.resize(frames);
for (size_t i = 0; i < frames; i++)
{
VkSemaphoreCreateInfo semaphoreInfo = {};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &g_RenderFinishSemaphores[i]) != VK_SUCCESS)
throw std::runtime_error("failed to create synchronization objects for a frame!");
}
}
void VulkanImguiSystem::Initialize()
{
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // 可选:启用键盘导航
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // 可选启用Docking
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // 可选:启用多视口
ImGui::StyleColorsDark();
ImGui_ImplSDL2_InitForVulkan(api::Window::Ptr()->GetPtr());
Backend& backend = VulkanAPI::Ptr()->GetBackend();
VulkanAPI* API = VulkanAPI::Ptr();
VulkanWindow* window = VulkanWindow::Ptr();
Backend& backend = API->GetBackend();
Queue* pQueue = backend.GetDevice().GetQueue(Queue::RenderQueue);
CreateDescriptorPool(backend.GetDevice().Ptr(), g_DescriptorPool);
VkDescriptorPool descriptorPool = CreateDescriptorPool(backend.GetDevice().Ptr());
VkRenderPass renderPass = CreateRenderPass(API->graph.mSurface.format, backend.GetDevice().Ptr());
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance = backend.GetInstance().Ptr();
init_info.PhysicalDevice = backend.GetDevice().GetPhysical();
init_info.Device = backend.GetDevice().Ptr();
init_info.QueueFamily = pQueue->QueueFamilyIndex();
init_info.Queue = pQueue->Ptr();
init_info.DescriptorPool = g_DescriptorPool;
init_info.DescriptorPool = descriptorPool;
init_info.MinImageCount = 2;
init_info.ImageCount = swapchainImageCount;
init_info.ImageCount = window->Swapchain()->FrameCount();
init_info.RenderPass = renderPass;
init_info.PipelineCache = VK_NULL_HANDLE;
init_info.Subpass = 0;
init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
init_info.Allocator = VK_NULL_HANDLE;
ImGui_ImplVulkan_Init(&init_info);
ImGui_ImplVulkan_Init(&init_info, renderPass);
g_RenderPass = renderPass;
auto& surfaces = window->Swapchain()->GetSurface();
//CreateFrameBuffer(API, renderPass, surfaces);
//CreateCommandPool(backend.GetDevice().Ptr(), pQueue->QueueFamilyIndex(), surfaces.size());
}
void VulkanImguiSystem::Finalize()
{
}
void VulkanImguiSystem::BeginEditorRender()
{
ImGui_ImplVulkan_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
}
void VulkanImguiSystem::EditorRender()
{
static float my_float = 0.5f;
ImGui::Begin("Hello, ImGui!");
ImGui::Text("This is some useful text.");
ImGui::SliderFloat("float", &my_float, 0.0f, 1.0f);
ImGui::End();
ImGui::Render();
}
void VulkanImguiSystem::EndEditorRender()
{
/*
VulkanAPI* API = VulkanAPI::Ptr();
uint32_t frame = API->context.frame;
CommandBuffer commandBuffer = CommandBuffer(g_CommandBuffers[frame]);
commandBuffer.Reset();
commandBuffer.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
VkRenderPassBeginInfo renderPassinfo = {};
renderPassinfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassinfo.renderPass = g_RenderPass;
renderPassinfo.framebuffer = g_FrameBuffers[frame];
renderPassinfo.renderArea.extent.width = API->graph.mSurface.width;
renderPassinfo.renderArea.extent.height = API->graph.mSurface.height;
renderPassinfo.clearValueCount = 0;
vkCmdBeginRenderPass(commandBuffer.Ptr(), &renderPassinfo, VK_SUBPASS_CONTENTS_INLINE);
// Record Imgui Draw Data and draw funcs into command buffer
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), commandBuffer.Ptr());
vkCmdEndRenderPass(commandBuffer.Ptr());
commandBuffer.EndRecord();
// 提交CommandBuffer
pmr::vector<VkPipelineStageFlags> waitStages{FramePool()};
waitStages.resize(renderAPI->curWaitSemaphores.size(), VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
vector<VkSemaphore> waitSemaphores = renderAPI->curWaitSemaphores;
waitStages.push_back(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
waitSemaphores.push_back(renderAPI->presentImageAvailableSemaphores[renderAPI->currentFrame]);
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pCommandBuffers = &commandBuffer.Ptr();
submitInfo.commandBufferCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores.data();
submitInfo.pWaitDstStageMask = waitStages.data();
submitInfo.waitSemaphoreCount = static_cast<uint32_t>(waitSemaphores.size());
submitInfo.pSignalSemaphores = &g_RenderFinishSemaphores[renderAPI->currentFrame];
submitInfo.signalSemaphoreCount = 1;
VkFence fence = renderAPI->inFlightFences[renderAPI->currentFrame];
if (vkQueueSubmit(renderAPI->graphicsQueue, 1, &submitInfo, fence) != VK_SUCCESS)
throw std::runtime_error("failed to submit draw command buffer!");
renderAPI->curWaitSemaphores = { g_RenderFinishSemaphores[renderAPI->currentFrame] };*/
}
}

View File

@ -22,7 +22,8 @@ namespace vkn {
args.width = mWidth;
args.height = mHeight;
mSwapchain = new (GlobalPool()) VulkanSwapchain(backend.GetDevice(), surface, args);
api->graph.mSurface = mSwapchain->mSurfaces[0];
api->context.frameCount = args.frames;
api->graph.InitSurface(mSwapchain->mSurfaces);
return true;
}
VulkanSwapchain::VulkanSwapchain(Device& device, VkSurfaceKHR surface, VulkanWindowArgs& args)
@ -88,7 +89,7 @@ namespace vkn {
VkFence surfaceFence = mFences[ctx.frame];
VkSemaphore surfaceSemaphore = mSemaphores[ctx.frame];
ctx.surface = mSurfaces[ctx.frame];
ctx.command = mCommands[ctx.frame];
ctx.surfaceCommand = mCommands[ctx.frame];
ctx.surfaceFence = surfaceFence;
ctx.surfaceSemaphore = surfaceSemaphore;
ctx.presentSemaphore = mSemaphores[ctx.frame + mFrames];

View File

@ -49,6 +49,13 @@ namespace vkn {
mPool.pop_back();
return buffer;
}
void CommandPool::PopList(vector<VkCommandBuffer>& list, int size)
{
list.reserve(size);
for (int i = 0; i < size; i++) {
list.push_back(AllocateBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY));
}
}
void CommandPool::Push(CommandBuffer& cmd)
{
cmd.Reset();

View File

@ -97,6 +97,13 @@ namespace vkn {
VkResult result = vkCreateSemaphore(mPtr, &semaphoreInfo, nullptr, &semaphore);
return semaphore;
}
void Device::CreateSemaphores(vector<VkSemaphore>& list, int size)
{
list.reserve(size);
for (int i = 0; i < size; i++) {
list.push_back(CreateSemaphore());
}
}
VkShaderModule Device::CreateShaderModule(const pmr::vector<char>& code)
{
VkShaderModuleCreateInfo createInfo = {};

View File

@ -1,6 +1,6 @@
shared_module("vulkan","engine")
add_headerfiles("include/**.h","include/**.inl")
add_files("src/**.cpp", "include/volk/volk.c")
add_headerfiles("include/**.h")
add_files("src/**.cpp", "include/volk/volk.c", "include/imgui/*.cpp")
add_packages("vulkansdk", {public = true})
add_dependency("engine", {public = true})
on_load(function (target)

View File

@ -2,10 +2,17 @@
#include "data/global.h"
#include "render/window.h"
#include "render/renderapi.h"
#include "imgui.h"
namespace api {
void EditorModule::OnLoad(int argc, char** argv)
{
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // 可选:启用键盘导航
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // 可选启用Docking
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // 可选:启用多视口
ImGui::StyleColorsDark();
}
void EditorModule::OnUnload()

View File

@ -3,6 +3,9 @@
#include "data/global.h"
#include "vkn/vulkan_window.h"
#include "vkn/vulkan_api.h"
#ifdef WITH_EDITOR
#include "imgui/imgui_impl_sdl2.h"
#endif
#include "render/pass/demo_pass.h"
#include <iostream>
using namespace api;
@ -20,8 +23,13 @@ void ZWorldModule::OnLoad(int argc, char** argv)
}
API->Init();
API->context.views.push_back({});
#ifdef WITH_EDITOR //绑定窗口交互
ImGui_ImplSDL2_InitForVulkan(window->GetPtr());
#endif
}
void ZWorldModule::Initialize()
{
}
void ZWorldModule::OnUnload()
{
}
@ -37,10 +45,11 @@ void ZWorldModule::MainLoop()
running = false;
}
}
API->graph.AddRenderPass<DemoPass>();
API->BeginFrame();
API->graph.AddRenderPass<DemoPass>();
API->Render();
API->EndFrame();
FramePool()->reset();
}
}

View File

@ -5,6 +5,7 @@ class ZWORLD_API ZWorldModule : public api::IMainModule
{
public:
void OnLoad(int argc, char** argv) override;
void Initialize()override;
void OnUnload() override;
void InitMetaData(void) override;
void MainLoop()override;