update thread_worker

This commit is contained in:
ouczbs 2024-08-27 20:21:32 +08:00
parent 25664db985
commit 8b234cd835
18 changed files with 234 additions and 133 deletions

View File

@ -5,7 +5,7 @@ namespace refl {
constexpr std::string_view func_signature() noexcept {
# if defined(__clang__)
auto sign = std::string_view{ __PRETTY_FUNCTION__ };
return sign.substr(53, sign.size() - 54);
return sign.substr(47, sign.size() - 47);
# elif defined(__GNUC__)
auto sign = std::string_view{ __PRETTY_FUNCTION__ };
return sign.substr(62, sign.size() - 62);

View File

@ -10,7 +10,7 @@ namespace refl {
parray(): m_cls(nullptr), m_ptr(nullptr),m_count(0) {}
template<typename C>
requires std::is_base_of_v<T, C>
parray(std::vector<C>& vec) : m_cls(&TypeInfo<C>::StaticClass), m_ptr(nullptr){
parray(std::vector<C>& vec) : m_cls(type_info<C>()), m_ptr(nullptr){
m_count = vec.size();
if (m_count > 0) {
C* ptr = new C[m_count];

View File

@ -3,7 +3,7 @@
#include <semaphore>
#include <concepts>
namespace zstd {
template<std::move_constructible T>
template<typename T>
class channel {
protected:
int m_tail;

View File

@ -0,0 +1,29 @@
#pragma once
#include "channel.h"
#include <thread>
namespace zstd{
template<typename value_type, typename Worker>
class ThreadWorker {
public:
using Element = value_type;
std::thread mThread;
channel<Element> mChannel;
void WorkLoop() {
mThread.detach();
}
void Loop() {
Worker* worker = dynamic_cast<Worker*>(this);
worker->Loop();
}
public:
ThreadWorker() : ThreadWorker(64) {}
ThreadWorker(int buffer) : mChannel(buffer)
{
mThread = std::thread(&ThreadWorker::WorkLoop, this);
}
void Invoke(const Element& elem) {
mChannel.release(elem);
}
};
}

View File

@ -1,5 +1,5 @@
#pragma once
#include "thread/worker.h"
#include "vkn/type.h"
namespace vkn {
class Device;
class Instance;
@ -7,16 +7,15 @@ namespace vkn {
protected:
Instance* mInstance;
Device* mDevice;
table<Name, CommandWorker*> mWorkerMap;
public:
Backend(string_view appName);
~Backend();
void InitWorker(Name name, VkCommandPoolCreateFlags flag);
CommandWorker* GetWorker(Name name);
template<typename Worker>
Worker* InitWorker(Name name, VkCommandPoolCreateFlags flag);
public:
static CommandWorker* TransferWorker;
static CommandWorker* RenderWorker;
static CommandWorker* PresentWorker;
static struct BufferWorker* TransferWorker;
static struct CommandWorker* RenderWorker;
static struct CommandWorker* PresentWorker;
};
};

View File

@ -0,0 +1,14 @@
#pragma once
#include "worker.h"
#include "vkn/wrapper/buffer.h"
namespace vkn {
class Device;
class Queue;
struct Buffer;
class BufferWorker : public ThreadWorker<Buffer, BufferWorker>{
public:
using ThreadWorker<Buffer, BufferWorker>::ThreadWorker;
void InitVmaAllocator(VkInstance instance);
void Loop();
};
};

View File

@ -0,0 +1,22 @@
#pragma once
#include "worker.h"
#include <semaphore>
namespace vkn {
class Device;
class Queue;
class CommandWorker : public ThreadWorker<voidFn, CommandWorker> {
protected:
std::binary_semaphore mSemaphore{0};
public:
using ThreadWorker<voidFn, CommandWorker>::ThreadWorker;
void InvokeBuffer(const commandFn& fn, const Element& callback);
void Buffer(CommandBuffer& cmd, const commandFn& fn, const Element& callback);
void Flush();
void ImmediatelyExecute(const commandFn& fn, const Element& callback) {
Buffer(mImmediateExeCmd, fn , callback);
}
bool Present(VkPresentInfoKHR& presentInfo);
void Loop();
void SyncInvoke(const Element& fn);
};
};

View File

@ -1,21 +0,0 @@
#pragma once
#include <thread>
#include "vkn/type.h"
#include <semaphore>
namespace vkn {
class CommandThreadWorker {
protected:
std::thread mThread;
Name mName;
channel<voidFn> mChannel;
std::binary_semaphore mSemaphore;
protected:
void workloop();
public:
CommandThreadWorker(Name name, int buffer);
~CommandThreadWorker();
void Invoke(const voidFn& fn);
void SyncInvoke(const voidFn& fn);
};
};

View File

@ -1,32 +1,31 @@
#pragma once
#include "std/thread.h"
#include "vkn/wrapper/commandpool.h"
#include "thread_worker.h"
#include "vkn/wrapper/queue.h"
namespace vkn {
class Device;
class Queue;
class CommandWorker {
using zstd::channel;
template<typename value_type, typename Worker>
class ThreadWorker : public zstd::ThreadWorker<value_type, Worker> {
protected:
Name mName;
Device& mDevice;
Queue& mQueue;
Name mName;
CommandThreadWorker mWork;
CommandPool mCommandPool;
CommandBuffer mImmediateExeCmd;
public:
CommandWorker(Name name, Device& device, Queue& queue, VkCommandPoolCreateFlags queueFlags);
ThreadWorker(Name name, Device& device, Queue& queue, VkCommandPoolCreateFlags queueFlags)
: zstd::ThreadWorker<value_type, Worker>(64)
, mName(name)
, mDevice(device)
, mQueue(queue)
, mCommandPool(device, queueFlags, queue.QueueFamilyIndex())
, mImmediateExeCmd(mCommandPool.AllocateBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY))
{}
CommandPool& GetCommandPool() {
return mCommandPool;
}
Queue& GetQueue() {
return mQueue;
}
void Invoke(const voidFn& fn);
void InvokeBuffer(const commandFn& fn, const voidFn& callback);
void Buffer(CommandBuffer& cmd, const commandFn& fn, const voidFn& callback);
void Flush();
void ImmediatelyExecute(const commandFn& fn, const voidFn callback) {
Buffer(mImmediateExeCmd, fn , callback);
}
bool Present(VkPresentInfoKHR& presentInfo);
};
};
}

View File

@ -1,5 +1,4 @@
#pragma once
#include "std/channel.h"
#include "pmr/frame_allocator.h"
#include "pmr/name.h"
#include <Windows.h>
@ -11,7 +10,6 @@ namespace vkn {
using pmr::Name;
using pmr::table;
using std::string_view;
using zstd::channel;
inline constexpr string_view VulkanEngineName = "vulkan";
class CommandBuffer;
using voidFn = std::function<void()>;

View File

@ -1,16 +1,20 @@
#pragma once
#include "type.h"
#include "asset/res/guid.h"
#include "render/renderapi.h"
#include "backend.h"
namespace vkn {
class Backend;
class VulkanWindow;
struct MeshVAO;
using api::Guid;
using api::Mesh;
using api::Shader;
class VULKAN_API VulkanAPI : public api::RenderAPI {
private:
VulkanWindow& window;
Backend backend;
table<Guid, MeshVAO> MeshTable;
public:
VulkanAPI();

View File

@ -0,0 +1,18 @@
#pragma once
#include "vkn/type.h"
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 {
VkBuffer* ppBuffer;
void* pCpuData;
VkBufferUsageFlags usage;
uint32_t size;
};
}

View File

@ -4,11 +4,19 @@
#include "vkn/wrapper/instance.h"
#include "vkn/wrapper/instance_create.h"
#include "vkn/wrapper/queue.h"
#include "vkn/thread/buffer_worker.h"
#include "vkn/thread/command_worker.h"
namespace vkn {
CommandWorker* Backend::TransferWorker;
BufferWorker* Backend::TransferWorker;
CommandWorker* Backend::RenderWorker;
CommandWorker* Backend::PresentWorker;
Backend::Backend(string_view appName) : mWorkerMap(GlobalPool())
template<typename Worker>
inline Worker* Backend::InitWorker(Name name, VkCommandPoolCreateFlags flag)
{
auto queue = mDevice->GetQueue(name);
return new Worker(name, *mDevice, *queue, flag);
}
Backend::Backend(string_view appName)
{
InstanceCreator instanceCreator{};
mInstance = new (GlobalPool()) Instance(instanceCreator);
@ -21,33 +29,14 @@ namespace vkn {
deviceCreator.AddQueue(Queue::PresentQueue, VkQueueFlagBits::VK_QUEUE_GRAPHICS_BIT, 1.0);
mDevice = new (GlobalPool()) Device(deviceCreator);
InitWorker(Queue::TransferQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
InitWorker(Queue::RenderQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
InitWorker(Queue::ComputeQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
InitWorker(Queue::PresentQueue, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT);
Backend::TransferWorker = GetWorker(Queue::TransferQueue);
Backend::RenderWorker = GetWorker(Queue::RenderQueue);
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()
{
mInstance->~Instance();
mDevice->~Device();
}
void Backend::InitWorker(Name name, VkCommandPoolCreateFlags flag)
{
auto queue = mDevice->GetQueue(name);
if (queue) {
auto worker = new CommandWorker(name, *mDevice, *queue, flag);
mWorkerMap.emplace(name, worker);
}
}
CommandWorker* Backend::GetWorker(Name name)
{
auto it = mWorkerMap.find(name);
if (it != mWorkerMap.end()) {
return it->second;
}
return nullptr;
}
}

View File

@ -0,0 +1,63 @@
#include "vkn/thread/buffer_worker.h"
#include "vkn/wrapper/queue.h"
#include "vkn/wrapper/device.h"
#include "vma/vk_mem_alloc.h"
#include "zlog.h"
namespace vkn {
static VmaAllocator vmaAllocator;
void BufferWorker::InitVmaAllocator(VkInstance instance)
{
// 因为用volk库手动加载所有Vulkan函数了所以这里要给VMA传递获取函数地址的方法让VMA可以正确获取Vulkan函数
VmaVulkanFunctions vmaVkFunctions = {};
vmaVkFunctions.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
vmaVkFunctions.vkGetDeviceProcAddr = vkGetDeviceProcAddr;
VmaAllocatorCreateInfo vmaInfo = {};
vmaInfo.vulkanApiVersion = VK_HEADER_VERSION_COMPLETE;
vmaInfo.instance = instance;
vmaInfo.physicalDevice = mDevice.GetPhysical();
vmaInfo.device = mDevice.Ptr();
vmaInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
// 如果不手动加载Vulkan函数这里可以填NULL
vmaInfo.pVulkanFunctions = &vmaVkFunctions;
vmaCreateAllocator(&vmaInfo, &vmaAllocator);
}
void BufferWorker::Loop()
{
while (true) {
Element elem = mChannel.acquire();
VkBufferCreateInfo bufferInfo = {};
bufferInfo.size = elem.size;
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocation stagingAllocation;
VmaAllocationCreateInfo allocationInfo = {};
allocationInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
VkBuffer stagingBuffer;
vmaCreateBuffer(vmaAllocator, &bufferInfo, &allocationInfo, &stagingBuffer, &stagingAllocation, nullptr);
// 将数据复制到 Staging Buffer
void* data;
vmaMapMemory(vmaAllocator, stagingAllocation, &data);
memcpy(data, elem.pCpuData, elem.size);
vmaUnmapMemory(vmaAllocator, stagingAllocation);
// 创建 GPU Buffer, GPU内部缓冲区访问速度非常快
VkBuffer& gpuBuffer = *elem.ppBuffer;
VmaAllocation gpuBufferAllocation;
bufferInfo.usage = elem.usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
allocationInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
vmaCreateBuffer(vmaAllocator, &bufferInfo, &allocationInfo, &gpuBuffer, &gpuBufferAllocation, nullptr);
// 复制数据
VkBufferCopy copyRegion = {};
copyRegion.size = elem.size;
vkCmdCopyBuffer(mImmediateExeCmd.Ptr(), stagingBuffer, gpuBuffer, 1, &copyRegion);
}
}
}

View File

@ -1,30 +1,15 @@
#include "vkn/thread/worker.h"
#include "vkn/wrapper/queue.h"
#include "vkn/thread/command_worker.h"
#include "vkn/wrapper/device.h"
namespace vkn {
CommandWorker::CommandWorker(Name name, Device& device, Queue& queue, VkCommandPoolCreateFlags queueFlags)
:mName(name)
,mDevice(device)
,mQueue(queue)
,mCommandPool(device, queueFlags, queue.QueueFamilyIndex())
,mWork(name, 64)
,mImmediateExeCmd(mCommandPool.AllocateBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY))
void CommandWorker::InvokeBuffer(const commandFn& fn, const Element& callback)
{
}
void CommandWorker::Invoke(const voidFn& fn)
{
mWork.Invoke(fn);
}
void CommandWorker::InvokeBuffer(const commandFn& fn, const voidFn& callback)
{
mWork.Invoke([=, this]() {
Invoke([=, this]() {
CommandBuffer cmd = mCommandPool.Pop();
Buffer(cmd, fn, callback);
mCommandPool.Push(cmd);
});
}
void CommandWorker::Buffer(CommandBuffer& cmd, const commandFn& fn, const voidFn& callback)
void CommandWorker::Buffer(CommandBuffer& cmd, const commandFn& fn, const Element& callback)
{
cmd.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
fn(cmd);
@ -37,11 +22,26 @@ namespace vkn {
void CommandWorker::Flush()
{
mWork.SyncInvoke([]{});
SyncInvoke([]{});
}
bool CommandWorker::Present(VkPresentInfoKHR& presentInfo)
{
VkResult result = vkQueuePresentKHR(mQueue.Ptr(), &presentInfo);
return result == VK_SUCCESS;
}
void CommandWorker::SyncInvoke(const Element& fn)
{
Invoke([=, this]() {
fn();
mSemaphore.release();
});
mSemaphore.acquire();
}
void CommandWorker::Loop()
{
while (true) {
Element elem = mChannel.acquire();
elem();
}
}
}

View File

@ -1,36 +0,0 @@
#include "vkn/thread/thread_worker.h"
#include "zlog.h"
namespace vkn {
CommandThreadWorker::CommandThreadWorker(Name name, int buffer)
: mName(name)
, mChannel(buffer)
, mSemaphore(0)
{
mThread = std::thread(&CommandThreadWorker::workloop, this);
}
CommandThreadWorker::~CommandThreadWorker() {
zlog::info("~CommandThreadWorker");
zlog::flush();
}
void CommandThreadWorker::workloop()
{
mThread.detach();
while (true) {
voidFn fn = mChannel.acquire();
fn();
}
}
void CommandThreadWorker::Invoke(const voidFn& fn)
{
mChannel.release(fn);
}
void CommandThreadWorker::SyncInvoke(const voidFn& fn)
{
Invoke([=,this]() {
fn();
mSemaphore.release();
});
mSemaphore.acquire();
}
}

View File

@ -1,5 +1,8 @@
#include "vkn/vulkan_api.h"
#include "vkn/vulkan_window.h"
#include "vkn/wrapper/buffer.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)
@ -16,12 +19,29 @@ namespace vkn {
}
void VulkanAPI::SetStaticMesh(Mesh& mesh)
{
auto Indices = mesh.GetIndices();
auto Vertices = mesh.GetVertices();
auto& Indices = mesh.GetIndices();
auto& Vertices = mesh.GetVertices();
MeshVAO& VAO = MeshTable[mesh.GetGuid()];
VAO.indexCount = Indices.size();
VAO.vertexCount = Vertices.size();
Buffer indexBuffer{};
indexBuffer.ppBuffer = &VAO.indexBuffer;
indexBuffer.pCpuData = Indices.data();
indexBuffer.size = sizeof(decltype(Indices[0])) * Indices.size();
indexBuffer.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
Backend::TransferWorker->Invoke(indexBuffer);
Buffer vertexBuffer{};
vertexBuffer.ppBuffer = &VAO.vertexBuffer;
vertexBuffer.pCpuData = Vertices.data();
vertexBuffer.size = Vertices.data_size();
vertexBuffer.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
Backend::TransferWorker->Invoke(vertexBuffer);
}
void VulkanAPI::DrawStaticMesh(Mesh& mesh)
{
}
void VulkanAPI::LoadShader(Shader& shader)
{

View File

@ -0,0 +1,3 @@
namespace vkn{
}