vulkan material system

This commit is contained in:
ouczbs 2024-11-26 20:29:29 +08:00
parent 78f2aa18bf
commit 42bd8b06b5
16 changed files with 271 additions and 62 deletions

View File

@ -43,5 +43,30 @@ namespace api {
Material* operator->() {
return mMaterial.Ptr();
}
template<typename T>
bool SetResource(MaterialResource* pResource, const T& t) {
if (!pResource) {
return false;
}
auto obj = pResource->obj;
#ifdef API_DEBUG
if (!obj.Check(meta_info<T>())) {
throw std::runtime_error("Error: SetResource with error class type");
}
#endif // API_DEBUG
*(obj.CastTo<T*>()) = t;
pResource->isDirty = true;
return true;
}
template<typename T>
bool SetStaticResource(Name name,const T& t) {
auto pResource = mInfo.staticBlock.FindMaterialResource(name);
return SetResource(pResource, t);
}
template<typename T>
bool SetClassResource(Name name, const T& t) {
auto pResource = mInfo.classBlock.FindMaterialResource(name);
return SetResource(pResource, t);
}
};
};

View File

@ -2,12 +2,19 @@
#include "vertex.h"
namespace api{
struct ubMetaInfo {
uint32_t set;
uint32_t binding;
bool isShared{false};
uint32_t set{0};
uint32_t binding{0};
bool isUnique{false};
static ubMetaInfo FromField(const refl::FieldPtr& field) {
refl::Any meta = field.GetMeta();
if (meta) {
return meta.CastTo<ubMetaInfo>();
}
return {};
}
};
struct ubSimple {
UPROPERTY({}, api::ubMetaInfo{ .set = 0, .binding = 0 })
UPROPERTY({}, api::ubMetaInfo{ .set = 0, .binding = 0 , .isUnique = true})
Vector4 uColor;
};
}

View File

@ -1,7 +1,8 @@
#pragma once
#include "pmr/name.h"
#include "refl/pch.h"
#include "tinyimageformat/tinyimageformat_base.h"
#include <cstdint>
//#include <algorithm>
namespace api {
using pmr::Name;
enum class GraphicsAPI
@ -97,16 +98,61 @@ namespace api {
VERTEX = 0x1,
FRAGMENT = 0x2,
};
struct MaterialInfo {
struct MaterialResource {
Name name;
bool isDirty;
bool isUnique;
refl::Any obj;
void* Ptr()const {
return (void*)obj.ptr;
}
uint32_t Size()const {
return obj.cls ? obj.cls->size : 0;
}
};
struct MaterialResourceBlock {
uint32_t count;
void* pHeader;
char* pFlag;
struct Header {
Name name;
uint32_t size;
void* pCpuData;
void* pMappingData;
};
uint32_t blockSize;
MaterialResource* pResource;
static MaterialResourceBlock FromFields(std::span<const refl::FieldPtr> fields);
operator bool() {
return pResource;
}
MaterialResource* FindMaterialResource(Name name) {
for (uint32_t i = 0; i < count; i++) {
MaterialResource* res = (pResource + i);
if (res->name == name) {
return res;
}
}
return nullptr;
}
void Upload(void** ppMappingAddr) {
for (uint32_t i = 0; i < count; i++) {
auto res = pResource[i];
if (res.isDirty || res.isUnique) {
memcpy(*(ppMappingAddr + i), res.Ptr(), res.Size());
}
}
}
};
struct MaterialGpuResourceBlock {
uint16_t blockSize;
uint16_t bufferOffset;
bool isInit;
void** pMappingAddr;
operator bool() {
return isInit;
}
void* BufferPtr() {
return (char*)pMappingAddr + bufferOffset;
}
};
struct MaterialInfo {
bool isInit = false;
MaterialGpuResourceBlock gpuBlock;
MaterialResourceBlock classBlock;
MaterialResourceBlock staticBlock;
};
struct ShaderDescriptorLayout {
Name name;

View File

@ -46,9 +46,8 @@ namespace api {
mesh->SetMaterial(material);
RenderAPI::Ptr()->SetStaticMesh(*mesh);
RenderAPI::Ptr()->SetUpMaterialInstance(mesh->GetMaterialInstance());
ResourceSystem::Ptr()->AddDirtyFile("/engine/assets/shader/simple.vert");
ResourceSystem::Ptr()->AddDirtyFile("/engine/assets/shader/simple.frag");
ResourceSystem::Ptr()->SaveDirtyFile();
auto materialInstance = mesh->GetMaterialInstance();
materialInstance.SetClassResource(Name("uColor"), Vector4{1,0,0,1});
}
auto& surface = graph.mSurface;
ctx->SetViewport(0.0f, 0.0f,(float)surface.width,(float)surface.height, 0.f, 1.f);

View File

@ -1,4 +1,39 @@
#include "render/type.h"
#include "render/asset/ubo.h"
#include <algorithm>
namespace api {
MaterialResourceBlock MaterialResourceBlock::FromFields(std::span<const refl::FieldPtr> fields)
{
uint32_t count = fields.size();
if (!count) {
return {};
}
uint32_t blockSize = meta_align_size(sizeof(MaterialResource) * count);
for (auto& field : fields) {
blockSize += meta_align_size(field.type->size);
}
MaterialResource* refResource = (MaterialResource*)xmalloc(blockSize);
char* pObj = (char*)refResource + meta_align_size(sizeof(MaterialResource) * count);
MaterialResource* pResource = refResource;
for (auto& field : fields) {
new(pResource)MaterialResource{};
pResource->name = field.name;
pResource->obj = field.Construct(pObj);
pResource->isDirty = false;
ubMetaInfo ub = ubMetaInfo::FromField(field);
pResource->isUnique = ub.isUnique;
pObj += meta_align_size(field.type->size);
pResource++;
}
if (count > 1) {
std::sort(refResource, refResource, [](const MaterialResource& res1, const MaterialResource& res2) {
return res1.name < res2.name;
});
}
return { count , blockSize , refResource };
}
}
#ifdef RENDER_API_VAL
#include "renderapi_impl.inl"
#include "window_impl.inl"
#endif //
#endif //

View File

@ -67,7 +67,7 @@ namespace api
};
auto FindFieldFn = [](FieldPtrSpan fieldList, uint32_t set, uint32_t binding) -> FindFieldResult{
for (auto& field : fieldList) {
ubMetaInfo info = field.GetMeta().CastTo<ubMetaInfo>();
ubMetaInfo info = ubMetaInfo::FromField(field);
if (info.set == set && info.binding == binding) {
return { &field , info};
}
@ -84,7 +84,6 @@ namespace api
layout.stageFlags = stage;
if (auto result = FindFieldFn(fieldList, layout.set, layout.binding)) {
layout.name = result.field->name;
layout.isShared = result.info.isShared;
}
return layout;
};

View File

@ -144,4 +144,15 @@ namespace refl{
memset(ptr, 0, size);
return true;
}
inline Any FieldPtr::Construct(void* ptr) const
{
Any obj{ ptr, type };
if (data.member.value && flag & FIELD_MEMBER_FLAG) {
obj.Construct(data.member.value);
}
else {
obj.Construct({});
}
return obj;
}
}

View File

@ -22,9 +22,10 @@ namespace refl {
enum FieldFlag :uint32_t {
FIELD_NONE_FLAG = 0,
FIELD_MEMBER_FLAG = 1 << 0,
FIELD_METHOD_FLAG = 1 << 1,
FIELD_METHOD_VALUE_FLAG = 1 << 2,
FIELD_CTOR_FLAG = 1 << 3,
FIELD_STATIC_MEMBER_FLAG = 1 << 1,
FIELD_METHOD_FLAG = 1 << 2,
FIELD_METHOD_VALUE_FLAG = 1 << 3,
FIELD_CTOR_FLAG = 1 << 4,
};
struct FieldPtr {
union Data
@ -42,12 +43,16 @@ namespace refl {
const UClass* type{};
Data data{};
uint32_t flag{};
bool IsStatic()const {
return flag & FIELD_STATIC_MEMBER_FLAG;
}
Offset GetOffset() const {
if (flag & FIELD_MEMBER_FLAG) {
return data.member.offset;
}
return 0;
}
Any Construct(void* ptr)const;
Any GetValue()const {
if (flag & FIELD_MEMBER_FLAG)
return data.member.value;

View File

@ -35,6 +35,9 @@ namespace refl {
template<typename T, typename Obj>
static FieldPtr MemberField(T Obj::* ptr, std::string_view name, const MemberData& data = {});
template<typename T, typename Obj>
static FieldPtr MemberField(T* ptr, std::string_view name, const MemberData& data = {});
template<typename R, typename ...Args>
static FieldPtr MethodField(R(*ptr)(Args...), std::string_view name, const MethodData& data = {});

View File

@ -57,6 +57,21 @@ namespace refl {
}
return FieldPtr{ name, cls, member, flag };
}
template<typename T, typename Obj>
inline FieldPtr MetaHelp::MemberField(T* ptr, std::string_view name, const MemberData& data)
{
const UClass* cls = meta_info<T>();
uint32_t flag = FIELD_STATIC_MEMBER_FLAG;
MemberData member;
member.offset = reinterpret_cast<std::size_t>(&(reinterpret_cast<const Obj*>(0)->*ptr));
if (data.value) {
member.value = data.value.New(MetaGlobalPool());
}
if (data.meta) {
member.meta = data.meta.New(MetaGlobalPool());
}
return FieldPtr{ name, cls, member, flag };
}
template<typename R, typename ...Args>
inline FieldPtr MetaHelp::MethodField(R(*ptr)(Args...), std::string_view name, const MethodData& data)
{

View File

@ -17,6 +17,7 @@ namespace refl {
enum EFieldFind :uint32_t {
FIND_ALL_FIELD = 0,
FIND_ALL_MEMBER,
FIND_ALL_MEMBER_WITH_STATIC,
FIND_ALL_METHOD,
FIND_FIELD,
FIND_CTOR,

View File

@ -178,16 +178,19 @@ namespace refl {
span<const FieldPtr> GetFields(EFieldFind find, const Name& name) const {
constexpr int length = std::tuple_size<FieldsType>::value;
constexpr int MemberCount = MetaImpl::MemberCount();
constexpr int AllMemberCount = MemberCount + MetaImpl::StaticMemberCount();
constexpr int CtorCount = MetaImpl::CtorCount();
switch (find) {
case EFieldFind::FIND_ALL_FIELD:
return span<const FieldPtr>(&Fields[0], length);
case EFieldFind::FIND_ALL_MEMBER:
return span<const FieldPtr>(&Fields[0], MemberCount);
case EFieldFind::FIND_ALL_MEMBER_WITH_STATIC:
return span<const FieldPtr>(&Fields[0], AllMemberCount);
case EFieldFind::FIND_ALL_METHOD:
return span<const FieldPtr>(&Fields[MemberCount + CtorCount], length - MemberCount - CtorCount);
return span<const FieldPtr>(&Fields[AllMemberCount + CtorCount], length - AllMemberCount - CtorCount);
case EFieldFind::FIND_CTOR:
return span<const FieldPtr>(&Fields[MemberCount], CtorCount);
return span<const FieldPtr>(&Fields[AllMemberCount], CtorCount);
case EFieldFind::FIND_FIELD:
for (int i = 0; i < length; i++) {
if (name == Fields[i].name) {
@ -196,14 +199,14 @@ namespace refl {
}
return {};
case EFieldFind::FIND_MEMBER:
for (int i = 0; i < MemberCount; i++) {
for (int i = 0; i < AllMemberCount; i++) {
if (name == Fields[i].name) {
return span<const FieldPtr>(&Fields[i], 1);
}
}
return {};
case EFieldFind::FIND_METHOD:
for (int i = MemberCount + CtorCount; i < length; i++) {
for (int i = AllMemberCount + CtorCount; i < length; i++) {
if (name == Fields[i].name) {
return span<const FieldPtr>(&Fields[i], 1);
}
@ -212,7 +215,7 @@ namespace refl {
case EFieldFind::FIND_METHODS:
{
int first = 0, count = 0;
for (int i = MemberCount + CtorCount; i < length; i++) {
for (int i = AllMemberCount + CtorCount; i < length; i++) {
if (name == Fields[i].name) {
if (!count) {
first = i;

View File

@ -21,6 +21,6 @@ namespace vkn {
static void Init();
api::ResourceBundle LoadFile(api::PackagePath handle, const api::MetaBundle& meta) override;
static uint32_t GetShaderLayout(VkDescriptorSetLayoutList& layoutList, pmr::vector<api::ShaderProgram*>& programList);
static void LoadShaderBuffer(pmr::vector<api::ShaderProgram*>& programList, MaterialInfo& info);
static void LoadShaderBuffer(VkDescriptorSetList& setList, pmr::vector<api::ShaderProgram*>& programList, MaterialInfo& info);
};
}

View File

@ -6,10 +6,12 @@
#include "render/asset/material.h"
#include "render/tool/glsl_to_spirv.h"
#include "render/asset/vertex.h"
#include "render/asset/ubo.h"
#include "os/file_handle.h"
#include ".render/vkmeta_vertex_gen.inl"
using namespace api;
namespace vkn {
table<Name, MaterialInfo> MaterialInfoTable;
void VulkanGlslLoader::Init()
{
refl::register_meta<PosVertex>();
@ -93,45 +95,91 @@ namespace vkn {
}
return count;
}
void VulkanGlslLoader::LoadShaderBuffer(pmr::vector<api::ShaderProgram*>& programList, MaterialInfo& info)
{
ShaderDescriptorSet descList{ FramePool() };
GlslToSpirv::GetShaderLayout(descList, programList);
VulkanAPI* API = VulkanAPI::Ptr();
size_t count = descList.size();
if (!count) {
return;
}
size_t header_size = meta_align_size(sizeof(MaterialInfo::Header) * count) + meta_align_size(sizeof(Buffer) * count) + meta_align_size(count);
size_t size = header_size;
for (auto& desc : descList) {
size += meta_align_size(desc.size);
}
size += meta_align_size(sizeof(Buffer) * count);
MaterialInfo::Header* pHeader = (MaterialInfo::Header*)BufferPool()->allocate(size, 8);
Buffer* pBuffer = (Buffer*)((char*)pHeader + meta_align_size(sizeof(MaterialInfo::Header) * count));
info.count = count;
info.pHeader = pHeader;
info.pFlag = (char*)pBuffer + meta_align_size(sizeof(Buffer) * count);
char* pData = (char*)pHeader + header_size;
for (auto& desc : descList) {
new(pHeader)MaterialInfo::Header{};
void InitMaterialGpuResourceBlock(MaterialGpuResourceBlock& block, std::span<const refl::FieldPtr> fields) {
block.isInit = true;
uint32_t count = fields.size();
block.bufferOffset = meta_align_size(sizeof(void*) * count);
uint32_t blockSize = block.bufferOffset + meta_align_size(sizeof(Buffer) * count);
block.pMappingAddr = (void**)BufferPool()->allocate(blockSize, 8);
Buffer* pBuffer = (Buffer*)block.BufferPtr();
void** ppMappingData = block.pMappingAddr;
for (auto& field : fields) {
new(pBuffer)Buffer{};
pHeader->name = desc.name;
pHeader->size = desc.size;
pHeader->pCpuData = pData;
BufferCreator creatorInfo{};
creatorInfo.pBuffer = &pBuffer->buffer;
creatorInfo.pAllocation = &pBuffer->allocation;
creatorInfo.ppCpuData = (void**) &pData;
creatorInfo.size = desc.size;
creatorInfo.ppCpuData = ppMappingData;
creatorInfo.size = field.type->size;
creatorInfo.memoryUsage = VMA_MEMORY_USAGE_AUTO;
creatorInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
Backend::TransferWorker->Invoke(creatorInfo);
pHeader++;
pData += meta_align_size(desc.size);
Backend::TransferWorker->CreateBuffer(creatorInfo);
ppMappingData++;
pBuffer++;
}
}
void BindDescriptorSetBuffer(MaterialGpuResourceBlock& block, const ShaderDescriptorSet& descList, const VkDescriptorSetList& setList) {
VkWriteDescriptorSet writeDescriptorSet[16] = {};
VkDescriptorBufferInfo bufferInfoList[16] = {};
uint32_t descCount = 0;
Buffer* buffer = (Buffer*)block.BufferPtr();
for (auto& desc : descList) {
auto& bufferInfo = bufferInfoList[descCount];
bufferInfo.offset = 0;
bufferInfo.range = desc.size;
bufferInfo.buffer = buffer->buffer;
auto& writeDesc = writeDescriptorSet[descCount];
writeDesc.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDesc.dstSet = setList[desc.set];
writeDesc.dstBinding = desc.binding;
writeDesc.descriptorType = vkApiGetDescriptorType(desc.type);
writeDesc.descriptorCount = 1;
writeDesc.pBufferInfo = &bufferInfo;
descCount++;
}
vkUpdateDescriptorSets(VulkanAPI::Ptr()->GetBackend().GetDevice().Ptr(), descCount, writeDescriptorSet, 0, nullptr);
}
MaterialInfo& FindMaterialStaticBlock(const refl::UClass* meta, std::span<const refl::FieldPtr> fields) {
auto it = MaterialInfoTable.find(meta->name);
if (it != MaterialInfoTable.end()) {
return it->second;
}
uint16_t classMember = 0, staticMember = 0;
for (auto& field : fields) {
if (field.IsStatic()) {
break;
}
classMember++;
}
MaterialResourceBlock staticBlock = MaterialResourceBlock::FromFields(fields.subspan(classMember, fields.size() - classMember));
MaterialInfo info{ {},{}, staticBlock };
MaterialInfoTable.emplace(meta->name, info);
return MaterialInfoTable[meta->name];
}
void VulkanGlslLoader::LoadShaderBuffer(VkDescriptorSetList& setList, pmr::vector<api::ShaderProgram*>& programList, MaterialInfo& material)
{
if (material.isInit) {
return;
}
material.isInit = true;
auto meta = refl::find_info(programList[0]->ubName());
if (!meta) {
return;
}
auto fields = meta->GetFields(refl::FIND_ALL_MEMBER_WITH_STATIC, Name(""));
auto& info = FindMaterialStaticBlock(meta, fields);
MaterialResourceBlock classBlock = MaterialResourceBlock::FromFields(fields.subspan(0, fields.size() - info.staticBlock.count));
if (!info.gpuBlock) {
ShaderDescriptorSet descList{ FramePool() };
GlslToSpirv::GetShaderLayout(descList, programList);
InitMaterialGpuResourceBlock(info.gpuBlock, fields);
BindDescriptorSetBuffer(info.gpuBlock, descList, setList);
}
material.classBlock = classBlock;
material.gpuBlock = info.gpuBlock;
material.staticBlock = info.staticBlock;
}
void vkShaderProgram::Load(const pmr::vector<uint32_t>& spirv)
{
VulkanAPI* API = VulkanAPI::Ptr();

View File

@ -73,17 +73,25 @@ namespace vkn {
vkCmdBindVertexBuffers(ptr, 0, 1, vertexBuffers, offsets);
vkCmdBindIndexBuffer(ptr, vulkanVAO.indexBuffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdBindPipeline(ptr, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline);
if(pipeline.descCount > 0)
if (pipeline.descCount > 0) {
auto& materialInst = mesh.GetMaterialInstance();
auto& materialInfo = materialInst.GetInfo();
auto& gpuBlock = materialInfo.gpuBlock;
uint32_t staticCount = materialInfo.staticBlock.count;
materialInfo.staticBlock.Upload(gpuBlock.pMappingAddr);
materialInfo.classBlock.Upload(gpuBlock.pMappingAddr + staticCount);
vkCmdBindDescriptorSets(ptr, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipelineLayout, 0, pipeline.descCount, pipeline.descList, 0, VK_NULL_HANDLE);
}
vkCmdDrawIndexed(ptr, vulkanVAO.indexCount, 1, 0, 0, 0);
}
void VulkanAPI::SetUpMaterialInstance(MaterialInstance& material)
{
Shader& shader = *material->GetShader();
VulkanPipeline& pipeline = PipelineTable[shader.GetGuid()];
pmr::vector<api::ShaderProgram*> programList{ FramePool() };
programList.push_back(shader.GetVertHandle().Ptr());
programList.push_back(shader.GetFragHandle().Ptr());
VulkanGlslLoader::LoadShaderBuffer(programList, material.GetInfo());
VulkanGlslLoader::LoadShaderBuffer(pipeline.descList, programList, material.GetInfo());
}
void VulkanAPI::LoadShader(Shader& shader, size_t passKey)
{

View File

@ -23,6 +23,10 @@ function _listen_gen_file(target, batch, template, macro, define)
genfile, sourcefile = batch[1], batch[2]
sourcefile = string.lower(sourcefile)
local dependfile = target:dependfile(genfile)
if false then
cmd_compile(batch[1], batch[2], template, macro, define)
return
end
depend.on_changed(
function()
cmd_compile(batch[1], batch[2], template, macro, define)