add imgui & set main viewport

This commit is contained in:
ouczbs 2024-12-26 16:45:02 +08:00
parent 6c7dc30711
commit 1bbddd1c7d
24 changed files with 3841 additions and 43 deletions

View File

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

View File

@ -0,0 +1,50 @@
#pragma once
#include "render/graph/frame_graph.h"
#include <imgui.h>
namespace api {
class EditorSystem;
struct RenderEditorContext {
EditorSystem* editor;
uint32_t frame;
uint32_t frameCount;
EditorSystem* operator->() {
return editor;
}
};
class EditorPanel {
public:
EditorPanel() = default;
~EditorPanel() = default;
virtual void DrawPanel(FrameGraph& graph, RenderEditorContext& ctx) = 0;
};
class EditorWindow {
protected:
std::vector<EditorPanel*> mPanels;
public:
EditorWindow() = default;
~EditorWindow() = default;
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)...);
mPanels.push_back(ptr);
return ptr;
}
};
class EDITOR_API EditorSystem : public ISystem
{
SINGLETON_IMPL(EditorSystem)
protected:
std::vector<EditorWindow*> mWindows;
public:
EditorSystem();
template<typename T, typename ... Args>
T* AddWindow(Args&&... args) {
T* ptr = new (GlobalPool()) T(std::forward<Args>(args)...);
mWindows.push_back(ptr);
return ptr;
}
ImTextureID AddTexture(FrameGraph& graph, TextureDesc& desc, TextureSampler sampler);
virtual ImTextureID AddTexture(ImageViewPtr imageview, SamplerPtr sampler, ResourceState state) = 0;
};
}

View File

@ -1,4 +0,0 @@
#pragma once
namespace api {
}

View File

@ -1,8 +0,0 @@
#pragma once
#include "render/editor_system.h"
namespace api {
class MenuBarPanel : public EditorPanel {
public:
void DrawPanel(FrameGraph& graph, RenderEditorContext& context) override;
};
}

View File

@ -1,10 +1,18 @@
#pragma once
#include "editor/editor_system.h"
#include "ui/ui_window.h"
namespace api {
class EditorMainWindow : public UIWindow {
class EditorMainUIWindow : public UIWindow {
public:
using UIWindow::UIWindow;
void InitializeComponent() override;
};
class EditorMainWindow : public EditorWindow {
public:
Noesis::Ptr<Noesis::IView> mView;
public:
EditorMainWindow();
void Draw(FrameGraph& graph, RenderEditorContext& ctx) override;
};
}

View File

@ -15,7 +15,7 @@ namespace api {
table<TextureSampler, void*> mTextureSamplerPool;
table<Tag, uint32_t> mTextureTagMap;
table<TextureKey, std::vector<TextureID>> mTextureKeyMap;//一张图不够用了
std::vector<TextureDesc> mTexturePool;
pmr::vector<TextureDesc> mTexturePool{GlobalPool()};
table<TextureViewKey, ImageViewPtr> mTextureViewPool;
pmr::vector<FrameGraphNodePtr> mNodes{FramePool()};
RenderPassNode* mFirstInputNode{ nullptr };

View File

@ -56,7 +56,7 @@ namespace api {
}
}
if (outputNodes.size() > 1) {
std::sort(outputNodes.begin(), outputNodes.end(), [](RenderPassNode* a, RenderPassNode* b) {
std::sort(outputNodes.begin(), outputNodes.end(), [](const RenderPassNode* a, const RenderPassNode* b) {
if (a->type != b->type) {
return a->type < b->type;
}
@ -105,6 +105,12 @@ namespace api {
result.clear();
seenNodes.clear();
}
std::sort(mNodes.begin(), mNodes.end(), [](const FrameGraphNodePtr& a, const FrameGraphNodePtr& b) {
if (a->type != b->type) {
return a->type < b->type;
}
return a < b;
});
if (mLastOutputNode) {
mFirstInputNode->flag |= RenderPassNodeFlag::FirstInput;
mLastOutputNode->flag |= RenderPassNodeFlag::LastOutput;

View File

@ -43,7 +43,8 @@ namespace api {
void UIRenderDevice::UpdateTexture(Noesis::Texture* texture, uint32_t level, uint32_t x, uint32_t y, uint32_t width, uint32_t height, const void* data)
{
UITexture* uiTex = (UITexture*)texture;
TextureUpdateArgs args{.x = x, .y = y, .width = width,.height = height, .data = data};
mApi->UpdateTexture(uiTex->desc, args, ResourceState::TRANSFER_DST);
}
void UIRenderDevice::BeginOffscreenRender()
{

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

@ -2,4 +2,8 @@ static_component("ui","engine")
add_headerfiles("include/**.h")
add_files("src/**.cpp")
add_deps("core", "asset", "zlib", "render")
add_packages("noesis", "stb", {public = true})
add_packages("noesis", "stb", {public = true})
if WITH_EDITOR then
add_files("include/imgui/*.cpp")
add_packages("imgui", {public = true})
end

View File

@ -0,0 +1,25 @@
#pragma once
#include "editor/editor_system.h"
#include "render/graph/frame_graph.h"
#include "vkn/vulkan_api.h"
namespace vkn {
using api::FrameGraph;
using api::RenderPassContext;
using api::RenderPassBuilder;
using api::RenderEditorContext;
class VulkanImguiEditor : public api::EditorSystem {
public:
void Initialize() override;
void Finalize() override;
ImTextureID AddTexture(ImageViewPtr imageview, SamplerPtr sampler, ResourceState state) 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, RenderPassBuilder& builder);
static void Execute(FrameGraph&, RenderPassContext&);
};
}

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

@ -0,0 +1,168 @@
#include "vkn/vulkan_imgui_editor.h"
#include "vkn/vulkan_window.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 "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 {
using namespace api;
static Name ImguiPassName{"ImguiPass"};
static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
// Vulkan的ImGui接入比较麻烦参考教程: https://frguthmann.github.io/posts/vulkan_imgui/
VkDescriptorPool CreateDescriptorPool(VkDevice device) {
VkDescriptorPoolSize pool_sizes[] =
{
{ VK_DESCRIPTOR_TYPE_SAMPLER, 1000 },
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 },
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 },
{ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 },
{ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 },
{ VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 },
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 },
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 },
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 },
{ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 },
{ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 }
};
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
pool_info.maxSets = 1000 * IM_ARRAYSIZE(pool_sizes);
pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes);
pool_info.pPoolSizes = pool_sizes;
VkDescriptorPool descriptorPool;
vkCreateDescriptorPool(device, &pool_info, VK_NULL_HANDLE, &descriptorPool);
return descriptorPool;
}
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_COLOR_ATTACHMENT_OPTIMAL;
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 = 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 VulkanImguiEditor::Initialize()
{
VulkanAPI* API = VulkanAPI::Ptr();
VulkanWindow* window = VulkanWindow::Ptr();
Backend& backend = API->GetBackend();
Queue* pQueue = backend.GetDevice().GetQueue(Queue::RenderQueue);
VkDescriptorPool descriptorPool = CreateDescriptorPool(backend.GetDevice().Ptr());
TextureDesc surface = API->context.surface;
VkRenderPass renderPass = CreateRenderPass(surface.format, backend.GetDevice().Ptr());
ImGui_ImplVulkan_InitInfo init_info = {};
init_info.Instance = backend.GetInstance().Ptr();
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 = descriptorPool;
init_info.MinImageCount = 2;
init_info.ImageCount = API->context.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);
API->SetRenderPassInfo(ImguiPassName, renderPass);
EventSystem::Ptr()->BeginRenderFrame.Subscribe(&VulkanImguiEditor::OnBeginRenderFrame, this);
}
void VulkanImguiEditor::Finalize()
{
}
ImTextureID VulkanImguiEditor::AddTexture(ImageViewPtr imageview, SamplerPtr sampler, ResourceState state)
{
VkDescriptorSet descriptorSet = ImGui_ImplVulkan_AddTexture((VkSampler)sampler, (VkImageView)imageview, vkApiGetImageLayout(state));
return reinterpret_cast<ImTextureID>(descriptorSet);
}
void VulkanImguiEditor::Render(FrameGraph& graph, RenderEditorContext& ctx)
{
for (auto win : mWindows)
{
win->Draw(graph, ctx);
}
}
void VulkanImguiEditor::OnBeginRenderFrame(FrameGraph& graph, uint32_t frame)
{
graph.mIsRenderEditorSurface = gEngineConfig.IsRenderEditorSurface;
if (gEngineConfig.IsRenderEditorSurface) {
graph.mEditorSurfaceID = graph.mSurfaceID;
graph.mSurfaceID = graph.GetTextureID(FrameGraph::NameEditorSurface, frame);
}
graph.AddRenderPass<VulkanImguiEditor>();
}
void VulkanImguiEditor::Setup(FrameGraph& graph, RenderPassBuilder& builder)
{
builder.Name(ImguiPassName)
.Type(RenderPassNodeType::Imgui, RenderPassNodeFlag::Output)
.Write(graph.GetRenderSurface(), ResourceState::COLOR_ATTACHMENT);
if (gEngineConfig.IsRenderEditorSurface) {
builder.Read(graph.GetSurface(), ResourceState::READ_ONLY);
}
}
void VulkanImguiEditor::Execute(FrameGraph& graph, RenderPassContext& context)
{
graph.GetRenderSurface().state = ResourceState::PRESENT;
ImGui_ImplVulkan_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
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;
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), ctx.command);
ImGuiIO& io = ImGui::GetIO();
// 更新并渲染平台窗口
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault(nullptr, ctx.command);
}
}
}

View File

@ -2,10 +2,17 @@
#include "vkn/vulkan_module.h"
#include "vkn/loader/vulkan_glsl_loader.h"
#include "pmr/frame_allocator.h"
#ifdef WITH_EDITOR
#include "vkn/vulkan_imgui_editor.h"
#endif // WITH_EDITOR
using namespace vkn;
void VulkanModule::OnLoad(int argc, char** argv)
{
VulkanGlslLoader::Init();
#ifdef WITH_EDITOR
AddSystem<VulkanImguiEditor>();
#endif // WITH_EDITOR
}
void VulkanModule::OnUnload()

View File

@ -1,8 +1,14 @@
shared_module("vulkan","engine")
add_headerfiles("include/**.h")
add_files("src/**.cpp", "include/volk/volk.c")
add_packages("vulkansdk", {public = true})
add_dependency("engine", {public = true})
if WITH_EDITOR then
add_deps("editor")
add_headerfiles("src/imgui/*.h")
add_files("src/**.cpp", "include/volk/volk.c")
else
add_files("src/**.cpp|imgui/*|vulkan_imgui_editor.cpp", "include/volk/volk.c")
end
on_load(function (target)
if is_plat("windows") then
target:add("defines", "VK_USE_PLATFORM_WIN32_KHR=1")

View File

@ -1,16 +1,19 @@
#include "editor/editor.h"
#include "editor/window/editor_main_window.h"
#include "ui/ui_render_device.h"
#include "event/event_system.h"
#include "os/file_manager.h"
#include <NoesisPCH.h>
#include "imgui.h"
namespace api {
using namespace Noesis;
Ptr<IView> mView;
void EditorModule::OnLoad(int argc, char** argv)
{
PackagePath editor_noesis{"/engine/assets/noesis"};
FileManager::Ptr()->Mount("editor_noesis", editor_noesis.RealPath().c_str());
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()
@ -18,17 +21,7 @@ namespace api {
}
void EditorModule::Initialize(void)
{
Ptr<FrameworkElement> xaml = GUI::LoadXaml<FrameworkElement>("/editor_noesis/Menu.xaml");
mView = GUI::CreateView(xaml);
mView->SetFlags(RenderFlags_PPAA | RenderFlags_LCD);
mView->SetSize(1024, 768);
//mView->GetRenderer()->Init(UIRenderDevice::Ptr());
EventSystem::Ptr()->BeginRenderFrame.Subscribe(mInfo.name, [](FrameGraph& graph, int32_t frame) {
//mView->Update(0.033);
//IRenderer* renderer = mView->GetRenderer();
//renderer->UpdateRenderTree();
//renderer->RenderOffscreen();
//renderer->Render();
});
EditorSystem* Editor = EditorSystem::Ptr();
Editor->AddWindow<EditorMainWindow>();
}
}

View File

@ -0,0 +1,14 @@
#include "editor/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,9 +1,88 @@
#include "editor/window/editor_main_window.h"
#include "ui/ui_render_device.h"
#include "event/event_system.h"
#include "data/global.h"
#include <NoesisPCH.h>
namespace api {
void EditorMainWindow::InitializeComponent()
using namespace Noesis;
void EditorMainUIWindow::InitializeComponent()
{
for (int i = 0; i < 1000; i++) {
int j = 1;
}
}
EditorMainWindow::EditorMainWindow()
{
Ptr<FrameworkElement> xaml = GUI::LoadXaml<FrameworkElement>("/editor_noesis/Menu.xaml");
mView = GUI::CreateView(xaml);
mView->SetFlags(RenderFlags_PPAA | RenderFlags_LCD);
mView->SetSize(1024, 768);
mView->GetRenderer()->Init(UIRenderDevice::Ptr());
}
TextureSampler sampler{
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR,
.wrapS = SamplerWrapMode::CLAMP_TO_EDGE,
.wrapT = SamplerWrapMode::CLAMP_TO_EDGE,
.wrapR = SamplerWrapMode::CLAMP_TO_EDGE,
.compareMode = SamplerCompareMode::COMPARE_TO_TEXTURE,
.compareFunc = SamplerCompareFunc::GE,
};
ImTextureID TextureIDList[10] = {};
void InitRenderSurface(FrameGraph& graph, uint32_t frameCount) {
static bool sInit = false;
if (sInit)
return;
sInit = true;
TextureDesc desc{};
desc.width = 512;
desc.height = 512;
desc.format = TinyImageFormat_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 | TextureUsage::SAMPLEABLE;
for (uint32_t i = 0; i < frameCount; i++) {
graph.SetResourceTexture(desc, FrameGraph::NameEditorSurface, i);
}
}
void EditorMainWindow::Draw(FrameGraph& graph, RenderEditorContext& ctx)
{
static float my_float = 0.5f;
TextureDesc renderSurface = graph.GetRenderSurface();
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowViewport(viewport->ID);
// 设置窗口的大小为屏幕的分辨率
ImGui::SetNextWindowSize(ImVec2(renderSurface.width, renderSurface.height));
// 设置窗口位置为左上角
ImGui::SetNextWindowPos(viewport->Pos);
ImGui::Begin("MainWindow", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
ImGui::Text("This is some useful text.");
ImGui::SliderFloat("float", &my_float, 0.0f, 1.0f);
if (gEngineConfig.IsRenderEditorSurface) {
TextureDesc surface = graph.GetSurface();
if (!TextureIDList[ctx.frame]) {
TextureIDList[ctx.frame] = ctx->AddTexture(graph, surface, sampler);
}
// 每帧渲染时都可以通过 ImTextureID 使用
ImGui::Image(TextureIDList[ctx.frame], ImVec2(surface.width, surface.height));
}
else {
gEngineConfig.IsRenderEditorSurface = true;
InitRenderSurface(graph, ctx.frameCount);
}
ImGui::End();
//mView->Update(0.033);
//IRenderer* renderer = mView->GetRenderer();
//renderer->UpdateRenderTree();
//renderer->RenderOffscreen();
//renderer->Render();
}
}

View File

@ -3,15 +3,18 @@
#include "ui/ui_render_device.h"
#include "xmalloc_new_delete.h"
namespace api {
class ENGINE_API EngineModule : public api::IDynamicModule
class ENGINE_API EngineModule : public IDynamicModule
{
public:
void OnLoad(int argc, char** argv) override {
#ifdef ENGINE_ROOT
api::FileManager::Ptr()->Mount("engine", TOSTRING(ENGINE_ROOT));
#endif
new UIRenderDevice(RenderAPI::Ptr());
};
void Initialize() override {
IDynamicModule::Initialize();
new UIRenderDevice(RenderAPI::Ptr());
}
void OnUnload() override {
};
void InitMetaData(void) override {

View File

@ -7,7 +7,6 @@ target("engine")
set_group("Engine")
add_rules("engine.api")
add_files("src/engine/**.cpp")
add_packages("noesis")
target("editor")
set_kind("shared")
set_group("Engine")
@ -15,7 +14,7 @@ target("editor")
add_headerfiles("include/editor/**.h","assets/noesis/*.xaml")
add_includedirs("include")
add_files("src/editor/**.cpp")
add_deps("engine",{public = true})
add_deps("engine", {public = true})
includes("xmake/xmake.lua")
includes("3rdparty/xmake.lua")
includes("tools/xmake.lua")

View File

@ -10,8 +10,19 @@ Size=191,71
Collapsed=0
[Window][MainWindow]
Pos=163,77
Size=695,351
Pos=0,0
Size=1080,720
Collapsed=0
[Window][ChildWindow]
ViewportPos=0,0
ViewportId=0x4CE55A22
Size=1080,720
Collapsed=0
[Window][Debug]
Pos=101,134
Size=545,504
Collapsed=0
[Docking][Data]

View File

@ -5,6 +5,9 @@
#include "vkn/vulkan_window.h"
#include "vkn/vulkan_api.h"
#include "render/pass/demo_pass.h"
#ifdef WITH_EDITOR
#include "imgui/imgui_impl_sdl2.h"
#endif
#include <iostream>
using namespace api;
RenderAPI* API;
@ -20,6 +23,9 @@ void ZWorldModule::OnLoad(int argc, char** argv)
window->CreateRender(args);
API->Init();
API->context.views.push_back({});
#ifdef WITH_EDITOR //绑定窗口交互
ImGui_ImplSDL2_InitForVulkan(window->GetPtr());
#endif
}
void ZWorldModule::InitMetaData()
{
@ -47,6 +53,9 @@ void ZWorldModule::MainLoop()
while (running) {
// 处理事件
while (SDL_PollEvent(&event_)) {
#ifdef WITH_EDITOR
ImGui_ImplSDL2_ProcessEvent(&event_);
#endif // WITH_EDITOR
if (event_.type == SDL_QUIT) {
running = false;
}