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 RenderPassBuilder;
public:
RscHandle<Texture> mSurface;
table<Name, RscHandle<Texture>> mResourceTable;
lemon::ListGraph mGraph;
pmr::vector<FrameGraphNodePtr> mNodes{FramePool()};
public:
@ -21,7 +23,13 @@ namespace api {
void Compile();
void Execute(FRenderView& view);
void Clear();
RscHandle<Texture> 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);

View File

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

View File

@ -9,10 +9,10 @@ namespace api {
class RENDER_API RenderAPI : public Singleton<RenderAPI>
{
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());

View File

@ -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,
};
}

View File

@ -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())

View File

@ -5,6 +5,7 @@
#include <functional>
#define VK_NO_PROTOTYPES
#include "volk/volk.h"
#include <render/type.h>
#define Z_RENDER_DEBUG 1
namespace vkn {
using pmr::Name;
@ -14,7 +15,7 @@ namespace vkn {
class CommandBuffer;
using voidFn = std::function<void()>;
using commandFn = std::function<void(CommandBuffer& cmd)>;
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
};
}

View File

@ -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<Guid, MeshVAO> MeshTable;
table<Guid, VkRenderPass> RenderPassCache;
public:
VulkanAPI();
@ -33,6 +34,8 @@ namespace vkn {
void BeginFrame()override;
void EndFrame()override;
VkRenderPass GetRenderPass(RenderPassKey config);
Backend& GetBackend() {
return backend;
}

View File

@ -2,12 +2,9 @@
#include "type.h"
#include "render/window.h"
#include <SDL2/SDL_vulkan.h>
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<VkSemaphore> 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); };
};
}

View File

@ -20,7 +20,5 @@ namespace vkn {
public:
static const Name TransferQueue;
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.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<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::PresentWorker = InitWorker<CommandWorker>(Queue::ComputeQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
Backend::TransferWorker->InitVmaAllocator(mInstance->Ptr());
}
Backend::~Backend()

View File

@ -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);
}
}

View File

@ -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 <algorithm>
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 };

View File

@ -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)
{

View File

@ -5,12 +5,11 @@
#include "render/pass/demo_pass.h"
#include <iostream>
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) {