This commit is contained in:
ouczbs 2024-09-07 17:48:12 +08:00
parent f8913cd7d2
commit d154ac2251
14 changed files with 127 additions and 35 deletions

View File

@ -8,6 +8,8 @@ namespace api {
class TextureBuilder; class TextureBuilder;
class RenderPassBuilder; class RenderPassBuilder;
public: public:
RscHandle<Texture> mSurface;
table<Name, RscHandle<Texture>> mResourceTable;
lemon::ListGraph mGraph; lemon::ListGraph mGraph;
pmr::vector<FrameGraphNodePtr> mNodes{FramePool()}; pmr::vector<FrameGraphNodePtr> mNodes{FramePool()};
public: public:
@ -21,7 +23,13 @@ namespace api {
void Compile(); void Compile();
void Execute(FRenderView& view); void Execute(FRenderView& view);
void Clear(); void Clear();
RscHandle<Texture> Resource(Name name) {
auto it = mResourceTable.find(name);
if (it == mResourceTable.end()) {
return {};
}
return it->second;
}
public: public:
void ExecuteRenderPass(RenderPassNode* node, FRenderView& view); void ExecuteRenderPass(RenderPassNode* node, FRenderView& view);
void ExecutePresentPass(RenderPassNode* node, FRenderView& view); void ExecutePresentPass(RenderPassNode* node, FRenderView& view);

View File

@ -41,8 +41,8 @@ namespace api {
}; };
struct FrameResource { struct FrameResource {
using Resource = std::variant<FrameTextureResource, void*>; using Resource = std::variant<FrameTextureResource, void*>;
Name name; Name name;
Resource resource; Resource resource;
FrameGraphNodePtr source; FrameGraphNodePtr source;
pmr::vector<FrameGraphNodePtr> targets{ FramePool() }; pmr::vector<FrameGraphNodePtr> targets{ FramePool() };
template<typename T> template<typename T>

View File

@ -9,10 +9,10 @@ namespace api {
class RENDER_API RenderAPI : public Singleton<RenderAPI> class RENDER_API RenderAPI : public Singleton<RenderAPI>
{ {
public: public:
RenderContext* ctx; RenderContext& context;
FrameGraph graph; FrameGraph graph;
RenderAPI() {}; RenderAPI(RenderContext* ctx) : context(*ctx){};
virtual ~RenderAPI() {}; virtual ~RenderAPI() { delete &context; };
public: public:
void* operator new(size_t size) { void* operator new(size_t size) {
return ::operator new(size, GlobalPool()); return ::operator new(size, GlobalPool());

View File

@ -17,4 +17,28 @@ namespace api {
return {}; 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,
};
} }

View File

@ -6,7 +6,7 @@ namespace api {
auto edge = graph.CreateTexture( auto edge = graph.CreateTexture(
[=](FrameGraph& graph, FrameGraph::TextureBuilder& builder) { [=](FrameGraph& graph, FrameGraph::TextureBuilder& builder) {
builder.Name("import") builder.Name("import")
.Import({}); .Import(graph.Resource("demo_input"));
}); });
builder.Name("DemoPass") builder.Name("DemoPass")
.Read(TextureDesc::Make()) .Read(TextureDesc::Make())

View File

@ -5,6 +5,7 @@
#include <functional> #include <functional>
#define VK_NO_PROTOTYPES #define VK_NO_PROTOTYPES
#include "volk/volk.h" #include "volk/volk.h"
#include <render/type.h>
#define Z_RENDER_DEBUG 1 #define Z_RENDER_DEBUG 1
namespace vkn { namespace vkn {
using pmr::Name; using pmr::Name;
@ -14,7 +15,7 @@ namespace vkn {
class CommandBuffer; class CommandBuffer;
using voidFn = std::function<void()>; using voidFn = std::function<void()>;
using commandFn = std::function<void(CommandBuffer& cmd)>; using commandFn = std::function<void(CommandBuffer& cmd)>;
static constexpr uint8_t MAX_SUPPORTED_RENDER_TARGET_COUNT = 8u;
struct MeshVAO struct MeshVAO
{ {
uint32_t indexCount = 0; // 索引数量 uint32_t indexCount = 0; // 索引数量
@ -23,4 +24,48 @@ namespace vkn {
VkBuffer vertexBuffer = VK_NULL_HANDLE; VkBuffer vertexBuffer = VK_NULL_HANDLE;
bool inUse = false; 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
};
} }

View File

@ -10,8 +10,7 @@ namespace vkn {
using api::Guid; using api::Guid;
using api::Mesh; using api::Mesh;
using api::Shader; using api::Shader;
class VulkanContext : public api::RenderContext { struct VulkanContext : public api::RenderContext {
public:
VkSemaphore surfaceSemaphore; VkSemaphore surfaceSemaphore;
}; };
class VULKAN_API VulkanAPI : public api::RenderAPI { class VULKAN_API VulkanAPI : public api::RenderAPI {
@ -19,6 +18,8 @@ namespace vkn {
VulkanWindow& window; VulkanWindow& window;
Backend backend; Backend backend;
table<Guid, MeshVAO> MeshTable; table<Guid, MeshVAO> MeshTable;
table<Guid, VkRenderPass> RenderPassCache;
public: public:
VulkanAPI(); VulkanAPI();
@ -33,6 +34,8 @@ namespace vkn {
void BeginFrame()override; void BeginFrame()override;
void EndFrame()override; void EndFrame()override;
VkRenderPass GetRenderPass(RenderPassKey config);
Backend& GetBackend() { Backend& GetBackend() {
return backend; return backend;
} }

View File

@ -2,12 +2,9 @@
#include "type.h" #include "type.h"
#include "render/window.h" #include "render/window.h"
#include <SDL2/SDL_vulkan.h> #include <SDL2/SDL_vulkan.h>
namespace api {
class RenderContext;
}
namespace vkn { namespace vkn {
class Device; class Device;
using RenderContext = api::RenderContext; struct VulkanContext;
struct VULKAN_API VulkanWindowArgs { struct VULKAN_API VulkanWindowArgs {
uint32_t frames; uint32_t frames;
uint32_t width; uint32_t width;
@ -30,8 +27,8 @@ namespace vkn {
pmr::vector<VkSemaphore> mSemaphores{ GlobalPool() }; pmr::vector<VkSemaphore> mSemaphores{ GlobalPool() };
public: public:
VulkanSwapchain(Device& device, VkSurfaceKHR surface, VulkanWindowArgs& args); VulkanSwapchain(Device& device, VkSurfaceKHR surface, VulkanWindowArgs& args);
void Aquire(RenderContext& ctx); void Aquire(VulkanContext& ctx);
void Present(RenderContext& ctx); void Present(VulkanContext& ctx);
}; };
class VULKAN_API VulkanWindow : public api::Window { class VULKAN_API VulkanWindow : public api::Window {
private: private:
@ -48,7 +45,7 @@ namespace vkn {
static VulkanWindow* Ptr() { static VulkanWindow* Ptr() {
return (VulkanWindow*)api::Window::Ptr(); return (VulkanWindow*)api::Window::Ptr();
} }
void Aquire(RenderContext& ctx) { mSwapchain->Aquire(ctx); } void Aquire(VulkanContext& ctx) { mSwapchain->Aquire(ctx); };
void Present(RenderContext& ctx) { mSwapchain->Present(ctx); }; void Present(VulkanContext& ctx) { mSwapchain->Present(ctx); };
}; };
} }

View File

@ -20,7 +20,5 @@ namespace vkn {
public: public:
static const Name TransferQueue; static const Name TransferQueue;
static const Name RenderQueue; static const Name RenderQueue;
static const Name ComputeQueue;
static const Name PresentQueue;
}; };
} }

View File

@ -23,15 +23,12 @@ namespace vkn {
DeviceCreator deviceCreator = DeviceCreator{ *mInstance }; DeviceCreator deviceCreator = DeviceCreator{ *mInstance };
deviceCreator.AddWindowExtension(); 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::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); mDevice = new (GlobalPool()) Device(deviceCreator);
Backend::TransferWorker = InitWorker<BufferWorker>(Queue::TransferQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); Backend::TransferWorker = InitWorker<BufferWorker>(Queue::TransferQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
Backend::RenderWorker = InitWorker<CommandWorker>(Queue::RenderQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); Backend::RenderWorker = InitWorker<CommandWorker>(Queue::RenderQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
Backend::PresentWorker = InitWorker<CommandWorker>(Queue::ComputeQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
Backend::TransferWorker->InitVmaAllocator(mInstance->Ptr()); Backend::TransferWorker->InitVmaAllocator(mInstance->Ptr());
} }
Backend::~Backend() Backend::~Backend()

View File

@ -1,11 +1,14 @@
#include "vkn/vulkan_api.h" #include "vkn/vulkan_api.h"
#include "vkn/vulkan_window.h" #include "vkn/vulkan_window.h"
#include "vkn/wrapper/buffer.h" #include "vkn/wrapper/buffer.h"
#include "vkn/wrapper/device.h"
#include "vkn/thread/buffer_worker.h" #include "vkn/thread/buffer_worker.h"
#include "vkn/thread/command_worker.h" #include "vkn/thread/command_worker.h"
#include "render/asset/mesh.h" #include "render/asset/mesh.h"
namespace vkn { 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() void VulkanAPI::BeginFrame()
{ {
window.Aquire(context); window.Aquire(*(VulkanContext*)&context);
} }
void VulkanAPI::EndFrame() 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);
} }
} }

View File

@ -3,6 +3,7 @@
#include "vkn/wrapper/instance.h" #include "vkn/wrapper/instance.h"
#include "vkn/vulkan_api.h" #include "vkn/vulkan_api.h"
#include "vkn/backend.h" #include "vkn/backend.h"
#include "vkn/thread/command_worker.h"
#include "zlog.h" #include "zlog.h"
#include <algorithm> #include <algorithm>
namespace vkn { namespace vkn {
@ -56,18 +57,23 @@ namespace vkn {
vkGetSwapchainImagesKHR(device.Ptr(), mPtr, &imageCount, nullptr); vkGetSwapchainImagesKHR(device.Ptr(), mPtr, &imageCount, nullptr);
swapchain_images.resize(imageCount); swapchain_images.resize(imageCount);
vkGetSwapchainImagesKHR(device.Ptr(), mPtr, &imageCount, swapchain_images.data()); 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]; VkFence surfaceFence = mFences[ctx.frame];
VkSemaphore surfaceSemaphore = mSemaphores[ctx.frame]; VkSemaphore surfaceSemaphore = mSemaphores[ctx.frame];
ctx.surfaceSemaphore = surfaceSemaphore;
if (vkWaitForFences(mDevice.Ptr(), 1, &surfaceFence, VK_TRUE, UINT64_MAX) != VK_SUCCESS) if (vkWaitForFences(mDevice.Ptr(), 1, &surfaceFence, VK_TRUE, UINT64_MAX) != VK_SUCCESS)
throw std::runtime_error("Failed to wait for fence!"); throw std::runtime_error("Failed to wait for fence!");
vkAcquireNextImageKHR(mDevice.Ptr(), mPtr, UINT64_MAX, surfaceSemaphore, VK_NULL_HANDLE, &ctx.presentFrame); vkAcquireNextImageKHR(mDevice.Ptr(), mPtr, UINT64_MAX, surfaceSemaphore, VK_NULL_HANDLE, &ctx.presentFrame);
vkResetFences(mDevice.Ptr(), 1, &surfaceFence); vkResetFences(mDevice.Ptr(), 1, &surfaceFence);
} }
void VulkanSwapchain::Present(RenderContext& ctx) void VulkanSwapchain::Present(VulkanContext& ctx)
{ {
VkSwapchainKHR swapChains[] = { mPtr }; VkSwapchainKHR swapChains[] = { mPtr };
VkSemaphore waitSemaphores[] = { ctx.surfaceSemaphore }; VkSemaphore waitSemaphores[] = { ctx.surfaceSemaphore };

View File

@ -2,8 +2,6 @@
namespace vkn { namespace vkn {
const Name Queue::TransferQueue = "transfer"; const Name Queue::TransferQueue = "transfer";
const Name Queue::RenderQueue = "render" ; const Name Queue::RenderQueue = "render" ;
const Name Queue::ComputeQueue = "computer";
const Name Queue::PresentQueue = "present" ;
Queue::Queue(Name name, uint32_t queueFamilyIndex, VkQueue queue) Queue::Queue(Name name, uint32_t queueFamilyIndex, VkQueue queue)
: mName(name) : mName(name)
{ {

View File

@ -5,12 +5,11 @@
#include "render/pass/demo_pass.h" #include "render/pass/demo_pass.h"
#include <iostream> #include <iostream>
using namespace api; using namespace api;
RenderAPI* API;
void ZWorldModule::OnLoad(int argc, char** argv) void ZWorldModule::OnLoad(int argc, char** argv)
{ {
// 创建窗口 // 创建窗口
auto window = new vkn::VulkanWindow(&SDL_CreateWindow, { "zengine" , SDL_WINDOW_VULKAN }, 1080, 720); 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(); auto args = vkn::VulkanWindowArgs::Default();
args.frames = 3; args.frames = 3;
if (!window->CreateRender(&SDL_Vulkan_CreateSurface, args)) { if (!window->CreateRender(&SDL_Vulkan_CreateSurface, args)) {
@ -21,11 +20,11 @@ void ZWorldModule::OnLoad(int argc, char** argv)
void ZWorldModule::OnUnload() void ZWorldModule::OnUnload()
{ {
API = nullptr;
} }
void ZWorldModule::MainLoop() void ZWorldModule::MainLoop()
{ {
RenderAPI* API = RenderAPI::Ptr();
bool running = true; bool running = true;
SDL_Event event_; SDL_Event event_;
while (running) { while (running) {