This commit is contained in:
ouczbs 2024-09-01 22:32:29 +08:00
parent f6e755ea3f
commit f8913cd7d2
21 changed files with 146 additions and 69 deletions

View File

@ -25,7 +25,6 @@ namespace api {
class ShaderProgram class ShaderProgram
, class Asset , class Asset
, class Texture , class Texture
, class FrameBuffer
>; >;
template<typename Resource> template<typename Resource>
concept is_resource_v = requires { typename Resource::BaseResource; }; concept is_resource_v = requires { typename Resource::BaseResource; };

View File

@ -2,4 +2,16 @@
#include "render/module.h" #include "render/module.h"
namespace api { namespace api {
IMPLEMENT_STATIC_MODULE(RENDER_API, RenderModule, render); IMPLEMENT_STATIC_MODULE(RENDER_API, RenderModule, render);
void RenderAPI::RenderView(FRenderView& view)
{
graph.Compile();
graph.Execute(view);
graph.Clear();
}
void RenderAPI::Render()
{
for (auto view : context.views) {
RenderView(view);
}
}
} }

View File

@ -1,11 +1,11 @@
#include "render/window.h" #include "render/window.h"
namespace api { namespace api {
inline Window::Window(CreatePFN func, const Args& args, int width, int height) noexcept : mHeight(height), mWidth(width) inline Window::Window(CreatePFN createPFN, const Args& args, int width, int height) noexcept : mHeight(height), mWidth(width)
{ {
uint32_t windowFlags = SDL_WINDOW_SHOWN; uint32_t windowFlags = args.windowFlags | SDL_WINDOW_SHOWN;
windowFlags |= args.resizeable ? SDL_WINDOW_RESIZABLE : 0; windowFlags |= args.resizeable ? SDL_WINDOW_RESIZABLE : 0;
windowFlags |= args.headless ? SDL_WINDOW_HIDDEN : 0; windowFlags |= args.headless ? SDL_WINDOW_HIDDEN : 0;
// Even if we're in headless mode, we still need to create a window, otherwise SDL will not poll events. // Even if we're in headless mode, we still need to create a window, otherwise SDL will not poll events.
mPtr = func(args.title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, windowFlags); mPtr = createPFN(args.title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, windowFlags);
} }
} }

View File

@ -1,17 +0,0 @@
#pragma once
#include "desc/attachment_desc.h"
namespace api {
class Attachment;
class FrameBuffer : public Resource<FrameBuffer>
{
public:
pmr::vector<Attachment*> mAttachments{};
Attachment* mDepthAttach{};
Attachment* mStencilAttach{};
Vector2 mSize;
public:
Vector2 Size() const { return mSize; }
const Attachment& DepthAttachment()const { return *mDepthAttach; }
const Attachment& GetAttachment(size_t index)const { return *mAttachments[index]; }
};
}

View File

@ -0,0 +1,8 @@
#pragma once
#include "asset/asset.h"
namespace api {
class Texture : public Resource<Texture>
{
public:
};
}

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "type.h" #include "type.h"
namespace api { namespace api {
struct FRenderView;
class FrameGraph class FrameGraph
{ {
public: public:
@ -18,13 +19,13 @@ namespace api {
FrameGraphEdgePtr CreateTexture(const TextureSetupFunction& setup); FrameGraphEdgePtr CreateTexture(const TextureSetupFunction& setup);
void Compile(); void Compile();
void Execute(); void Execute(FRenderView& view);
void Clear(); void Clear();
public: public:
void ExecuteRenderPass(RenderPassNode* node); void ExecuteRenderPass(RenderPassNode* node, FRenderView& view);
void ExecutePresentPass(RenderPassNode* node); void ExecutePresentPass(RenderPassNode* node, FRenderView& view);
void ExecuteComputePass(RenderPassNode* node); void ExecuteComputePass(RenderPassNode* node, FRenderView& view);
void ExecuteCopyPass(RenderPassNode* node); void ExecuteCopyPass(RenderPassNode* node, FRenderView& view);
}; };
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "render/asset/framebuffer.h" #include "asset/asset.h"
#include "render/type.h"
#include "lemon/list_graph.h" #include "lemon/list_graph.h"
#include <functional> #include <functional>
namespace api { namespace api {

View File

@ -1,7 +1,13 @@
#pragma once #pragma once
#include "type.h" #include "type.h"
namespace api { namespace api {
struct RenderContext;
struct FRenderView {
RenderContext* context;
};
struct RenderContext { struct RenderContext {
pmr::vector<FRenderView> views;
uint32_t frame{ 0 };
uint32_t presentFrame{ 0 };
}; };
} }

View File

@ -2,14 +2,15 @@
#include "singleton.h" #include "singleton.h"
#include "pmr/frame_allocator.h" #include "pmr/frame_allocator.h"
#include "render_context.h" #include "render_context.h"
#include "graph/frame_graph.h"
namespace api { namespace api {
class Mesh; class Mesh;
class Shader; class Shader;
class Camera;
class RenderNode;
class RENDER_API RenderAPI : public Singleton<RenderAPI> class RENDER_API RenderAPI : public Singleton<RenderAPI>
{ {
public: public:
RenderContext* ctx;
FrameGraph graph;
RenderAPI() {}; RenderAPI() {};
virtual ~RenderAPI() {}; virtual ~RenderAPI() {};
public: public:
@ -28,5 +29,7 @@ namespace api {
virtual void BeginFrame() = 0; virtual void BeginFrame() = 0;
virtual void EndFrame() = 0; virtual void EndFrame() = 0;
virtual void RenderView(FRenderView& view);
void Render();
}; };
} }

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <cstdint>
namespace api { namespace api {
enum class GraphicsAPI enum class GraphicsAPI
{ {
@ -6,4 +7,14 @@ namespace api {
Vulkan, Vulkan,
D3D12 D3D12
}; };
struct TextureDesc {
static TextureDesc Make() {
return {};
}
};
struct AttachmentDesc {
static AttachmentDesc Make() {
return {};
}
};
} }

View File

@ -11,6 +11,7 @@ namespace api {
SDL_Window* mPtr = nullptr; SDL_Window* mPtr = nullptr;
struct Args { struct Args {
const char* title; const char* title;
uint32_t windowFlags = 0;
bool resizeable = true; bool resizeable = true;
bool headless = false; bool headless = false;
}; };

View File

@ -1,4 +0,0 @@
#include "render/asset/framebuffer.h"
namespace api {
}

View File

@ -0,0 +1,4 @@
#include "render/asset/texture.h"
namespace api {
}

View File

@ -27,21 +27,21 @@ namespace api {
}); });
mNodes.erase(end, mNodes.end()); mNodes.erase(end, mNodes.end());
} }
void FrameGraph::Execute() void FrameGraph::Execute(FRenderView& view)
{ {
for (auto node : mNodes) { for (auto node : mNodes) {
switch (node.type) { switch (node.type) {
case FrameGraphNodePtr::Render: case FrameGraphNodePtr::Render:
ExecuteRenderPass(node.node); ExecuteRenderPass(node.node, view);
break; break;
case FrameGraphNodePtr::Present: case FrameGraphNodePtr::Present:
ExecuteComputePass(node.node); ExecuteRenderPass(node.node, view);
break; break;
case FrameGraphNodePtr::Compute: case FrameGraphNodePtr::Compute:
ExecuteRenderPass(node.node); ExecuteComputePass(node.node, view);
break; break;
case FrameGraphNodePtr::Copy: case FrameGraphNodePtr::Copy:
ExecuteCopyPass(node.node); ExecuteCopyPass(node.node, view);
break; break;
} }
} }
@ -51,22 +51,22 @@ namespace api {
mGraph.clear(); mGraph.clear();
mNodes.clear(); mNodes.clear();
} }
void FrameGraph::ExecuteRenderPass(RenderPassNode* node) void FrameGraph::ExecuteRenderPass(RenderPassNode* node, FRenderView& view)
{ {
RenderPassContext context{}; RenderPassContext context{};
std::get<RenderPassExecuteFunction>(node->executor)(*this, context); std::get<RenderPassExecuteFunction>(node->executor)(*this, context);
} }
void FrameGraph::ExecutePresentPass(RenderPassNode* node) void FrameGraph::ExecutePresentPass(RenderPassNode* node, FRenderView& view)
{ {
RenderPassContext context{}; RenderPassContext context{};
std::get<RenderPassExecuteFunction>(node->executor)(*this, context); std::get<RenderPassExecuteFunction>(node->executor)(*this, context);
} }
void FrameGraph::ExecuteComputePass(RenderPassNode* node) void FrameGraph::ExecuteComputePass(RenderPassNode* node, FRenderView& view)
{ {
ComputePassContext context{}; ComputePassContext context{};
std::get<ComputePassExecuteFunction>(node->executor)(*this, context); std::get<ComputePassExecuteFunction>(node->executor)(*this, context);
} }
void FrameGraph::ExecuteCopyPass(RenderPassNode* node) void FrameGraph::ExecuteCopyPass(RenderPassNode* node, FRenderView& view)
{ {
CopyPassContext context{}; CopyPassContext context{};
std::get<CopyPassExecuteFunction>(node->executor)(*this, context); std::get<CopyPassExecuteFunction>(node->executor)(*this, context);

View File

@ -14,4 +14,13 @@ 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)>;
struct MeshVAO
{
uint32_t indexCount = 0; // 索引数量
VkBuffer indexBuffer = VK_NULL_HANDLE;
uint32_t vertexCount = 0; // 顶点数量
VkBuffer vertexBuffer = VK_NULL_HANDLE;
bool inUse = false;
};
} }

View File

@ -10,6 +10,10 @@ 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 {
public:
VkSemaphore surfaceSemaphore;
};
class VULKAN_API VulkanAPI : public api::RenderAPI { class VULKAN_API VulkanAPI : public api::RenderAPI {
private: private:
VulkanWindow& window; VulkanWindow& window;

View File

@ -1,9 +1,14 @@
#pragma once #pragma once
#include "type.h" #include "type.h"
#include "render/window.h" #include "render/window.h"
#include <SDL2/SDL_vulkan.h>
namespace api {
class RenderContext;
}
namespace vkn { namespace vkn {
class Device; class Device;
struct VulkanWindowArgs { using RenderContext = api::RenderContext;
struct VULKAN_API VulkanWindowArgs {
uint32_t frames; uint32_t frames;
uint32_t width; uint32_t width;
uint32_t height; uint32_t height;
@ -25,9 +30,10 @@ 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 Present(RenderContext& ctx);
}; };
class VulkanWindow : public api::Window { class VULKAN_API VulkanWindow : public api::Window {
private: private:
VulkanSwapchain* mSwapchain; VulkanSwapchain* mSwapchain;
public: public:
@ -37,9 +43,12 @@ namespace vkn {
void operator delete(void* p) {} void operator delete(void* p) {}
public: public:
using api::Window::Window; using api::Window::Window;
void CreateRender(VulkanWindowArgs& args); using CreatePFN = decltype(&SDL_Vulkan_CreateSurface);
bool CreateRender(CreatePFN createPFN, VulkanWindowArgs& args);
static VulkanWindow* Ptr() { static VulkanWindow* Ptr() {
return (VulkanWindow*)api::Window::Ptr(); return (VulkanWindow*)api::Window::Ptr();
} }
void Aquire(RenderContext& ctx) { mSwapchain->Aquire(ctx); }
void Present(RenderContext& ctx) { mSwapchain->Present(ctx); };
}; };
} }

View File

@ -1,14 +1,6 @@
#pragma once #pragma once
#include "vkn/type.h" #include "vkn/type.h"
namespace vkn { namespace vkn {
struct MeshVAO
{
uint32_t indexCount = 0; // 索引数量
VkBuffer indexBuffer = VK_NULL_HANDLE;
uint32_t vertexCount = 0; // 顶点数量
VkBuffer vertexBuffer = VK_NULL_HANDLE;
bool inUse = false;
};
struct Buffer { struct Buffer {
VkBuffer* ppBuffer; VkBuffer* ppBuffer;
void* pCpuData; void* pCpuData;

View File

@ -48,10 +48,10 @@ namespace vkn {
} }
void VulkanAPI::BeginFrame() void VulkanAPI::BeginFrame()
{ {
window.Aquire(context);
} }
void VulkanAPI::EndFrame() void VulkanAPI::EndFrame()
{ {
window.Present(context);
} }
} }

View File

@ -4,21 +4,21 @@
#include "vkn/vulkan_api.h" #include "vkn/vulkan_api.h"
#include "vkn/backend.h" #include "vkn/backend.h"
#include "zlog.h" #include "zlog.h"
#include <SDL2/SDL_vulkan.h>
#include <algorithm> #include <algorithm>
namespace vkn { namespace vkn {
void VulkanWindow::CreateRender(VulkanWindowArgs& args) bool VulkanWindow::CreateRender(CreatePFN createPFN, VulkanWindowArgs& args)
{ {
VulkanAPI* api = VulkanAPI::Ptr(); VulkanAPI* api = VulkanAPI::Ptr();
Backend& backend = api->GetBackend(); Backend& backend = api->GetBackend();
VkInstance instance = backend.GetInstance().Ptr(); VkInstance instance = backend.GetInstance().Ptr();
VkSurfaceKHR surface; VkSurfaceKHR surface;
if (!SDL_Vulkan_CreateSurface(mPtr, instance, &surface)) { if (!createPFN(mPtr, instance, &surface)) {
zlog::error("SDL_Vulkan_CreateSurface failed! {}", SDL_GetError()); return false;
} }
args.width = mWidth; args.width = mWidth;
args.height = mHeight; args.height = mHeight;
mSwapchain = new (GlobalPool()) VulkanSwapchain(backend.GetDevice(), surface, args); mSwapchain = new (GlobalPool()) VulkanSwapchain(backend.GetDevice(), surface, args);
return true;
} }
VulkanSwapchain::VulkanSwapchain(Device& device, VkSurfaceKHR surface, VulkanWindowArgs& args) VulkanSwapchain::VulkanSwapchain(Device& device, VkSurfaceKHR surface, VulkanWindowArgs& args)
: mDevice(device) : mDevice(device)
@ -50,9 +50,37 @@ namespace vkn {
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
zlog::error("Failed to create swap chain."); zlog::error("Failed to create swap chain.");
} }
pmr::vector<VkImage> swapchain_images{FramePool()};
mFrames = args.frames; mFrames = args.frames;
pmr::vector<VkImage> swapchain_images{ FramePool() };
uint32_t imageCount = 0;
vkGetSwapchainImagesKHR(device.Ptr(), mPtr, &imageCount, nullptr);
swapchain_images.resize(imageCount);
vkGetSwapchainImagesKHR(device.Ptr(), mPtr, &imageCount, swapchain_images.data());
}
void VulkanSwapchain::Aquire(RenderContext& ctx)
{
VkFence surfaceFence = mFences[ctx.frame];
VkSemaphore surfaceSemaphore = mSemaphores[ctx.frame];
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)
{
VkSwapchainKHR swapChains[] = { mPtr };
VkSemaphore waitSemaphores[] = { ctx.surfaceSemaphore };
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.pWaitSemaphores = waitSemaphores;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.swapchainCount = 1;
presentInfo.pImageIndices = &ctx.presentFrame;
presentInfo.pResults = VK_NULL_HANDLE;
Backend::RenderWorker->Present(presentInfo);
ctx.frame = (ctx.frame + 1) % mFrames;
} }
VkExtent2D VulkanWindowArgs::EnableImageExtent2D(VkSurfaceCapabilitiesKHR& capabilities) VkExtent2D VulkanWindowArgs::EnableImageExtent2D(VkSurfaceCapabilitiesKHR& capabilities)
{ {

View File

@ -1,25 +1,33 @@
#include "zlog.h"
#include "zworld.h" #include "zworld.h"
#include "vkn/vulkan_window.h" #include "vkn/vulkan_window.h"
#include "vkn/vulkan_api.h" #include "vkn/vulkan_api.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)
{ {
// 创建窗口 // 创建窗口
new vkn::VulkanWindow(&SDL_CreateWindow, { "zengine" }, 1080, 720); auto window = new vkn::VulkanWindow(&SDL_CreateWindow, { "zengine" , SDL_WINDOW_VULKAN }, 1080, 720);
new vkn::VulkanAPI(); API = new vkn::VulkanAPI();
auto args = vkn::VulkanWindowArgs::Default();
args.frames = 3;
if (!window->CreateRender(&SDL_Vulkan_CreateSurface, args)) {
zlog::errorf("SDL_Vulkan_CreateSurface failed {}", SDL_GetError());
}
API->context.views.push_back({});
} }
void ZWorldModule::OnUnload() void ZWorldModule::OnUnload()
{ {
API = nullptr;
} }
void ZWorldModule::MainLoop() void ZWorldModule::MainLoop()
{ {
bool running = true; bool running = true;
SDL_Event event_; SDL_Event event_;
auto RenderAPI = RenderAPI::Ptr();
while (running) { while (running) {
// 处理事件 // 处理事件
while (SDL_PollEvent(&event_)) { while (SDL_PollEvent(&event_)) {
@ -27,7 +35,9 @@ void ZWorldModule::MainLoop()
running = false; running = false;
} }
} }
RenderAPI->BeginFrame(); API->graph.AddRenderPass<DemoPass>();
RenderAPI->EndFrame(); API->BeginFrame();
API->Render();
API->EndFrame();
} }
} }