diff --git a/engine/modules/engine/render/include/render/graph/frame_graph.h b/engine/modules/engine/render/include/render/graph/frame_graph.h index 0ea6e5b..999882c 100644 --- a/engine/modules/engine/render/include/render/graph/frame_graph.h +++ b/engine/modules/engine/render/include/render/graph/frame_graph.h @@ -8,6 +8,8 @@ namespace api { class TextureBuilder; class RenderPassBuilder; public: + RscHandle mSurface; + table> mResourceTable; lemon::ListGraph mGraph; pmr::vector mNodes{FramePool()}; public: @@ -21,7 +23,13 @@ namespace api { void Compile(); void Execute(FRenderView& view); void Clear(); - + RscHandle Resource(Name name) { + auto it = mResourceTable.find(name); + if (it == mResourceTable.end()) { + return {}; + } + return it->second; + } public: void ExecuteRenderPass(RenderPassNode* node, FRenderView& view); void ExecutePresentPass(RenderPassNode* node, FRenderView& view); diff --git a/engine/modules/engine/render/include/render/graph/type.h b/engine/modules/engine/render/include/render/graph/type.h index bd5b95c..9947fa0 100644 --- a/engine/modules/engine/render/include/render/graph/type.h +++ b/engine/modules/engine/render/include/render/graph/type.h @@ -41,8 +41,8 @@ namespace api { }; struct FrameResource { using Resource = std::variant; - Name name; - Resource resource; + Name name; + Resource resource; FrameGraphNodePtr source; pmr::vector targets{ FramePool() }; template diff --git a/engine/modules/engine/render/include/render/renderapi.h b/engine/modules/engine/render/include/render/renderapi.h index 67be439..4f006b8 100644 --- a/engine/modules/engine/render/include/render/renderapi.h +++ b/engine/modules/engine/render/include/render/renderapi.h @@ -9,10 +9,10 @@ namespace api { class RENDER_API RenderAPI : public Singleton { public: - RenderContext* ctx; + RenderContext& context; FrameGraph graph; - RenderAPI() {}; - virtual ~RenderAPI() {}; + RenderAPI(RenderContext* ctx) : context(*ctx){}; + virtual ~RenderAPI() { delete &context; }; public: void* operator new(size_t size) { return ::operator new(size, GlobalPool()); diff --git a/engine/modules/engine/render/include/render/type.h b/engine/modules/engine/render/include/render/type.h index 0a13a10..67e15bb 100644 --- a/engine/modules/engine/render/include/render/type.h +++ b/engine/modules/engine/render/include/render/type.h @@ -17,4 +17,28 @@ namespace api { return {}; } }; + enum class RenderLayout : uint8_t { + // The initial layout after the creation of the VkImage. We use this to denote the state before + // any transition. + UNDEFINED, + // Fragment/vertex shader accessible layout for reading and writing. + READ_WRITE, + // Fragment/vertex shader accessible layout for reading only. + READ_ONLY, + // For the source of a copy operation. + TRANSFER_SRC, + // For the destination of a copy operation. + TRANSFER_DST, + // For using a depth texture as an attachment. + DEPTH_ATTACHMENT, + // For using a depth texture both as an attachment and as a sampler. + DEPTH_SAMPLER, + // For swapchain images that will be presented. + PRESENT, + // For color attachments, but also used when the image is a sampler. + // TODO: explore separate layout policies for attachment+sampling and just attachment. + COLOR_ATTACHMENT, + // For color attachment MSAA resolves. + COLOR_ATTACHMENT_RESOLVE, + }; } \ No newline at end of file diff --git a/engine/modules/engine/render/src/pass/demo_pass.cpp b/engine/modules/engine/render/src/pass/demo_pass.cpp index 53e1b5c..eb8f313 100644 --- a/engine/modules/engine/render/src/pass/demo_pass.cpp +++ b/engine/modules/engine/render/src/pass/demo_pass.cpp @@ -6,7 +6,7 @@ namespace api { auto edge = graph.CreateTexture( [=](FrameGraph& graph, FrameGraph::TextureBuilder& builder) { builder.Name("import") - .Import({}); + .Import(graph.Resource("demo_input")); }); builder.Name("DemoPass") .Read(TextureDesc::Make()) diff --git a/engine/modules/render/vulkan/include/vkn/type.h b/engine/modules/render/vulkan/include/vkn/type.h index 347cbb6..498e2b5 100644 --- a/engine/modules/render/vulkan/include/vkn/type.h +++ b/engine/modules/render/vulkan/include/vkn/type.h @@ -5,6 +5,7 @@ #include #define VK_NO_PROTOTYPES #include "volk/volk.h" +#include #define Z_RENDER_DEBUG 1 namespace vkn { using pmr::Name; @@ -14,7 +15,7 @@ namespace vkn { class CommandBuffer; using voidFn = std::function; using commandFn = std::function; - + static constexpr uint8_t MAX_SUPPORTED_RENDER_TARGET_COUNT = 8u; struct MeshVAO { uint32_t indexCount = 0; // 索引数量 @@ -23,4 +24,48 @@ namespace vkn { VkBuffer vertexBuffer = VK_NULL_HANDLE; bool inUse = false; }; + enum class TargetBufferFlags : uint32_t { + NONE = 0x0u, //!< No buffer selected. + COLOR0 = 0x00000001u, //!< Color buffer selected. + COLOR1 = 0x00000002u, //!< Color buffer selected. + COLOR2 = 0x00000004u, //!< Color buffer selected. + COLOR3 = 0x00000008u, //!< Color buffer selected. + COLOR4 = 0x00000010u, //!< Color buffer selected. + COLOR5 = 0x00000020u, //!< Color buffer selected. + COLOR6 = 0x00000040u, //!< Color buffer selected. + COLOR7 = 0x00000080u, //!< Color buffer selected. + + COLOR = COLOR0, //!< \deprecated + COLOR_ALL = COLOR0 | COLOR1 | COLOR2 | COLOR3 | COLOR4 | COLOR5 | COLOR6 | COLOR7, + DEPTH = 0x10000000u, //!< Depth buffer selected. + STENCIL = 0x20000000u, //!< Stencil buffer selected. + DEPTH_AND_STENCIL = DEPTH | STENCIL, //!< depth and stencil buffer selected. + ALL = COLOR_ALL | DEPTH | STENCIL //!< Color, depth and stencil buffer selected. + }; + + struct alignas(8) RenderPassKey { + // For each target, we need to know three image layouts: the layout BEFORE the pass, the + // layout DURING the pass, and the layout AFTER the pass. Here are the rules: + // - For depth, we explicitly specify all three layouts. + // - Color targets have their initial image layout specified with a bitmask. + // - For each color target, the pre-existing layout is either UNDEFINED (0) or GENERAL (1). + // - The render pass and final images layout for color buffers is always + // VulkanLayout::COLOR_ATTACHMENT. + uint8_t initialColorLayoutMask; + + // Note that if VulkanLayout grows beyond 16, we'd need to up this. + api::RenderLayout initialDepthLayout : 8; + uint8_t padding0; + uint8_t padding1; + + VkFormat colorFormat[MAX_SUPPORTED_RENDER_TARGET_COUNT]; // 32 bytes + VkFormat depthFormat; // 4 bytes + TargetBufferFlags clear; // 4 bytes + TargetBufferFlags discardStart; // 4 bytes + TargetBufferFlags discardEnd; // 4 bytes + uint8_t samples; // 1 byte + uint8_t needsResolveMask; // 1 byte + uint8_t subpassMask; // 1 byte + uint8_t viewCount; // 1 byte + }; } diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_api.h b/engine/modules/render/vulkan/include/vkn/vulkan_api.h index ef044de..7539bb8 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_api.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_api.h @@ -10,8 +10,7 @@ namespace vkn { using api::Guid; using api::Mesh; using api::Shader; - class VulkanContext : public api::RenderContext { - public: + struct VulkanContext : public api::RenderContext { VkSemaphore surfaceSemaphore; }; class VULKAN_API VulkanAPI : public api::RenderAPI { @@ -19,6 +18,8 @@ namespace vkn { VulkanWindow& window; Backend backend; table MeshTable; + table RenderPassCache; + public: VulkanAPI(); @@ -33,6 +34,8 @@ namespace vkn { void BeginFrame()override; void EndFrame()override; + VkRenderPass GetRenderPass(RenderPassKey config); + Backend& GetBackend() { return backend; } diff --git a/engine/modules/render/vulkan/include/vkn/vulkan_window.h b/engine/modules/render/vulkan/include/vkn/vulkan_window.h index 5001ff4..4775c8b 100644 --- a/engine/modules/render/vulkan/include/vkn/vulkan_window.h +++ b/engine/modules/render/vulkan/include/vkn/vulkan_window.h @@ -2,12 +2,9 @@ #include "type.h" #include "render/window.h" #include -namespace api { - class RenderContext; -} namespace vkn { class Device; - using RenderContext = api::RenderContext; + struct VulkanContext; struct VULKAN_API VulkanWindowArgs { uint32_t frames; uint32_t width; @@ -30,8 +27,8 @@ namespace vkn { pmr::vector mSemaphores{ GlobalPool() }; public: VulkanSwapchain(Device& device, VkSurfaceKHR surface, VulkanWindowArgs& args); - void Aquire(RenderContext& ctx); - void Present(RenderContext& ctx); + void Aquire(VulkanContext& ctx); + void Present(VulkanContext& ctx); }; class VULKAN_API VulkanWindow : public api::Window { private: @@ -48,7 +45,7 @@ namespace vkn { static VulkanWindow* Ptr() { return (VulkanWindow*)api::Window::Ptr(); } - void Aquire(RenderContext& ctx) { mSwapchain->Aquire(ctx); } - void Present(RenderContext& ctx) { mSwapchain->Present(ctx); }; + void Aquire(VulkanContext& ctx) { mSwapchain->Aquire(ctx); }; + void Present(VulkanContext& ctx) { mSwapchain->Present(ctx); }; }; } \ No newline at end of file diff --git a/engine/modules/render/vulkan/include/vkn/wrapper/queue.h b/engine/modules/render/vulkan/include/vkn/wrapper/queue.h index 7c30fdd..523be2d 100644 --- a/engine/modules/render/vulkan/include/vkn/wrapper/queue.h +++ b/engine/modules/render/vulkan/include/vkn/wrapper/queue.h @@ -20,7 +20,5 @@ namespace vkn { public: static const Name TransferQueue; static const Name RenderQueue; - static const Name ComputeQueue; - static const Name PresentQueue; }; } \ No newline at end of file diff --git a/engine/modules/render/vulkan/src/backend.cpp b/engine/modules/render/vulkan/src/backend.cpp index e69466a..d479825 100644 --- a/engine/modules/render/vulkan/src/backend.cpp +++ b/engine/modules/render/vulkan/src/backend.cpp @@ -23,15 +23,12 @@ namespace vkn { DeviceCreator deviceCreator = DeviceCreator{ *mInstance }; deviceCreator.AddWindowExtension(); - deviceCreator.AddQueue(Queue::TransferQueue,VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT, 1.0); + deviceCreator.AddQueue(Queue::TransferQueue,VkQueueFlagBits::VK_QUEUE_TRANSFER_BIT, 1.0); deviceCreator.AddQueue(Queue::RenderQueue, VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT, 1.0); - deviceCreator.AddQueue(Queue::ComputeQueue, VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT, 1.0); - deviceCreator.AddQueue(Queue::PresentQueue, VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT, 1.0); mDevice = new (GlobalPool()) Device(deviceCreator); Backend::TransferWorker = InitWorker(Queue::TransferQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); Backend::RenderWorker = InitWorker(Queue::RenderQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); - Backend::PresentWorker = InitWorker(Queue::ComputeQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); Backend::TransferWorker->InitVmaAllocator(mInstance->Ptr()); } Backend::~Backend() diff --git a/engine/modules/render/vulkan/src/vulkan_api.cpp b/engine/modules/render/vulkan/src/vulkan_api.cpp index 1fb5eea..4c28ef3 100644 --- a/engine/modules/render/vulkan/src/vulkan_api.cpp +++ b/engine/modules/render/vulkan/src/vulkan_api.cpp @@ -1,11 +1,14 @@ #include "vkn/vulkan_api.h" #include "vkn/vulkan_window.h" #include "vkn/wrapper/buffer.h" +#include "vkn/wrapper/device.h" #include "vkn/thread/buffer_worker.h" #include "vkn/thread/command_worker.h" #include "render/asset/mesh.h" namespace vkn { - VulkanAPI::VulkanAPI() : window(*VulkanWindow::Ptr()), backend(VulkanEngineName) + VulkanAPI::VulkanAPI() : RenderAPI(new VulkanContext()) + , window(*VulkanWindow::Ptr()) + , backend(VulkanEngineName) { } @@ -48,10 +51,24 @@ namespace vkn { } void VulkanAPI::BeginFrame() { - window.Aquire(context); + window.Aquire(*(VulkanContext*)&context); } void VulkanAPI::EndFrame() { - window.Present(context); + window.Present(*(VulkanContext*)&context); + } + VkRenderPass VulkanAPI::GetRenderPass(RenderPassKey config) { + // Finally, create the VkRenderPass. + VkRenderPassCreateInfo renderPassInfo{ + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 0u, + .pAttachments = attachments, + .subpassCount = hasSubpasses ? 2u : 1u, + .pSubpasses = subpasses, + .dependencyCount = hasSubpasses ? 1u : 0u, + .pDependencies = dependencies + }; + VkRenderPass renderPass; + VkResult error = vkCreateRenderPass(backend.GetDevice().Ptr(), &renderPassInfo, nullptr, &renderPass); } } diff --git a/engine/modules/render/vulkan/src/vulkan_window.cpp b/engine/modules/render/vulkan/src/vulkan_window.cpp index a2eebca..d0e858e 100644 --- a/engine/modules/render/vulkan/src/vulkan_window.cpp +++ b/engine/modules/render/vulkan/src/vulkan_window.cpp @@ -3,6 +3,7 @@ #include "vkn/wrapper/instance.h" #include "vkn/vulkan_api.h" #include "vkn/backend.h" +#include "vkn/thread/command_worker.h" #include "zlog.h" #include namespace vkn { @@ -56,18 +57,23 @@ namespace vkn { vkGetSwapchainImagesKHR(device.Ptr(), mPtr, &imageCount, nullptr); swapchain_images.resize(imageCount); vkGetSwapchainImagesKHR(device.Ptr(), mPtr, &imageCount, swapchain_images.data()); - + for (int i = 0; i < mFrames; i++) { + //mSurfaces.push_back(new Image(Creator.device, "swapchain" + to_string(i), swapchain_images[i], args)); + mSemaphores.push_back(mDevice.CreateSemaphore()); + mFences.push_back(mDevice.CreateFence(VK_FENCE_CREATE_SIGNALED_BIT)); + } } - void VulkanSwapchain::Aquire(RenderContext& ctx) + void VulkanSwapchain::Aquire(VulkanContext& ctx) { VkFence surfaceFence = mFences[ctx.frame]; VkSemaphore surfaceSemaphore = mSemaphores[ctx.frame]; + ctx.surfaceSemaphore = surfaceSemaphore; if (vkWaitForFences(mDevice.Ptr(), 1, &surfaceFence, VK_TRUE, UINT64_MAX) != VK_SUCCESS) throw std::runtime_error("Failed to wait for fence!"); vkAcquireNextImageKHR(mDevice.Ptr(), mPtr, UINT64_MAX, surfaceSemaphore, VK_NULL_HANDLE, &ctx.presentFrame); vkResetFences(mDevice.Ptr(), 1, &surfaceFence); } - void VulkanSwapchain::Present(RenderContext& ctx) + void VulkanSwapchain::Present(VulkanContext& ctx) { VkSwapchainKHR swapChains[] = { mPtr }; VkSemaphore waitSemaphores[] = { ctx.surfaceSemaphore }; diff --git a/engine/modules/render/vulkan/src/wrapper/queue.cpp b/engine/modules/render/vulkan/src/wrapper/queue.cpp index d8c11b1..d70e54e 100644 --- a/engine/modules/render/vulkan/src/wrapper/queue.cpp +++ b/engine/modules/render/vulkan/src/wrapper/queue.cpp @@ -2,8 +2,6 @@ namespace vkn { const Name Queue::TransferQueue = "transfer"; const Name Queue::RenderQueue = "render" ; - const Name Queue::ComputeQueue = "computer"; - const Name Queue::PresentQueue = "present" ; Queue::Queue(Name name, uint32_t queueFamilyIndex, VkQueue queue) : mName(name) { diff --git a/game/zworld/src/zworld.cpp b/game/zworld/src/zworld.cpp index 00c7b9f..6ce2b06 100644 --- a/game/zworld/src/zworld.cpp +++ b/game/zworld/src/zworld.cpp @@ -5,12 +5,11 @@ #include "render/pass/demo_pass.h" #include using namespace api; -RenderAPI* API; void ZWorldModule::OnLoad(int argc, char** argv) { // 创建窗口 auto window = new vkn::VulkanWindow(&SDL_CreateWindow, { "zengine" , SDL_WINDOW_VULKAN }, 1080, 720); - API = new vkn::VulkanAPI(); + RenderAPI* API = new vkn::VulkanAPI(); auto args = vkn::VulkanWindowArgs::Default(); args.frames = 3; if (!window->CreateRender(&SDL_Vulkan_CreateSurface, args)) { @@ -21,11 +20,11 @@ void ZWorldModule::OnLoad(int argc, char** argv) void ZWorldModule::OnUnload() { - API = nullptr; } void ZWorldModule::MainLoop() { + RenderAPI* API = RenderAPI::Ptr(); bool running = true; SDL_Event event_; while (running) {