19 Commits

Author SHA1 Message Date
6820ee8c74 completed AutoMergeMaterialInstance,test ok. next step is to support texture2d array 2023-09-20 21:53:30 +08:00
ddb5a0b77a use VIL instead of MI in to sort for RenderNode 2023-09-20 18:56:09 +08:00
69646971ce used VIL instead of MI in MaterialRenderList 2023-09-20 17:19:46 +08:00
e71ec4be85 Added few RenderPass::CreatePipeline functions. 2023-09-20 17:15:13 +08:00
dbe2370a44 1.used uvec2/ushort2 in AssignVBO
2.completed first step then merge MI buffer
2023-09-20 15:55:14 +08:00
00d2677066 update RenderAssignBuffer,but can't run. 2023-09-19 22:04:34 +08:00
4208e47534 newly material instance stat,but can't run. 2023-09-19 21:45:54 +08:00
2dedeaad90 layouted codes of VKMaterialInstance.h 2023-09-19 21:45:28 +08:00
083600a95f added mi_max_count in Material 2023-09-19 21:44:48 +08:00
902dc20340 used ActiveMemoryBlockManager to manage data of material instances in Material class. 2023-09-19 21:09:09 +08:00
164498446a fixed crash in RenderAssignBuffer.cpp because not check ubo_mi before use. 2023-09-19 21:07:07 +08:00
cef5ad073b a few update 2023-09-07 18:09:31 +08:00
c2279c553d fixed a spell error in word. 2023-09-06 17:06:12 +08:00
d959e7988d moved few values to VKRenderAssign.h 2023-09-06 16:55:04 +08:00
202bff5870 moved few codes to RenderAssignBuffer.cpp from MaterialRenderList.cpp 2023-09-06 16:24:05 +08:00
8437d8d561 named values and macro about RenderAssignBuffer 2023-09-06 15:57:52 +08:00
714fc3dcb7 use hgl_min in MaterialCreateInfo.cpp 2023-09-05 23:36:59 +08:00
e030738a5f removed old codes of L2W in AssignBuffer 2023-09-05 20:52:55 +08:00
28b2b53d03 renamed to RenderAssignBuffer from RenderExtraBuffer 2023-09-05 20:48:47 +08:00
26 changed files with 504 additions and 396 deletions

2
CMCore

Submodule CMCore updated: 6a21b387f5...072153aa91

2
CMUtil

Submodule CMUtil updated: ff819d8a60...c0990c52eb

View File

@@ -10,10 +10,10 @@
set_property(TARGET ${name} PROPERTY FOLDER "ULRE/Example/Vulkan/${group}")
endmacro()
CreateProject("Basic" 1st_draw_triangle_in_NDC first_triangle.cpp)
CreateProject("Basic" 2nd_draw_triangle_use_UBO second_triangle.cpp)
CreateProject("Basic" 3rd_draw_triangle_use_RenderList third_triangle.cpp)
CreateProject("Basic" 4th_draw_triangle_use_MaterialInstance fourth_triangle.cpp)
CreateProject("Basic" 1st_draw_triangle_in_NDC first_triangle.cpp)
CreateProject("Basic" 2nd_draw_triangle_use_UBO second_triangle.cpp)
CreateProject("Basic" 3rd_AutoInstance third_triangle.cpp)
CreateProject("Basic" 4th_AutoMergeMaterialInstance fourth_triangle.cpp)
#CreateProject("Basic" FragCoord FragCoordTest.cpp)
#CreateProject("Basic" indices_rect indices_rect.cpp)

View File

@@ -1,5 +1,5 @@
// fourth_triangle
// 该范例主要演示使用材质实例传递颜色参数绘制三角形
// AutoMergeMaterialInstance
// 该范例主要演示使用一个材质下的不同材质实例传递颜色参数绘制三角形并依赖RenderList中的自动合并功能让同一材质下所有不同材质实例的对象一次渲染完成。
#include"VulkanAppFramework.h"
#include<hgl/math/Math.h>
@@ -7,6 +7,7 @@
#include<hgl/graph/VKRenderablePrimitiveCreater.h>
#include<hgl/graph/mtl/2d/Material2DCreateConfig.h>
#include<hgl/graph/RenderList.h>
#include<hgl/color/Color.h>
using namespace hgl;
using namespace hgl::graph;
@@ -23,15 +24,7 @@ constexpr float position_data[VERTEX_COUNT*2]=
0.1, 0.9
};
constexpr float color_data[6][4]=
{
{1,0,0,1},
{1,1,0,1},
{0,1,0,1},
{0,1,1,1},
{0,0,1,1},
{1,0,1,1},
};
constexpr uint DRAW_OBJECT_COUNT=12;
class TestApp:public VulkanApplicationFramework
{
@@ -40,8 +33,13 @@ private:
SceneNode render_root;
RenderList * render_list =nullptr;
MaterialInstance * material_instance[6]{};
Renderable * render_obj[6] {};
Material * material =nullptr;
struct
{
MaterialInstance * mi;
Renderable * r;
}render_obj[DRAW_OBJECT_COUNT]{};
Pipeline * pipeline =nullptr;
@@ -57,42 +55,48 @@ private:
AutoDelete<mtl::MaterialCreateInfo> mci=mtl::CreatePureColor2D(&cfg);
/* for(uint i=0;i<6;i++)
{
material_instance[i]=db->CreateMaterialInstance(mci);
material=db->CreateMaterial(mci);
if(!material_instance[i])
if(!material)
return(false);
for(uint i=0;i<DRAW_OBJECT_COUNT;i++)
{
render_obj[i].mi=db->CreateMaterialInstance(material);
if(!render_obj[i].mi)
return(false);
material_instance[i]->SetFloat4(0,color_data[i]);
}*/
Color4f color=GetColor4f((COLOR)(i+int(COLOR::Blue)),1.0);
render_obj[i].mi->WriteMIData(color,sizeof(Color4f)); //设置MaterialInstance的数据
}
}
// pipeline=db->CreatePipeline(material_instance,sc_render_target,OS_TEXT("res/pipeline/solid2d"));
// pipeline=CreatePipeline(material_instance,InlinePipeline::Solid2D,Prim::Triangles); //等同上一行为Framework重载默认使用swapchain的render target
pipeline=CreatePipeline(material,InlinePipeline::Solid2D,Prim::Triangles);
return pipeline;
}
bool InitVBO()
{
//RenderablePrimitiveCreater rpc(db,VERTEX_COUNT);
RenderablePrimitiveCreater rpc(db,VERTEX_COUNT);
//if(!rpc.SetVBO(VAN::Position, VF_V2F, position_data))return(false);
//
//render_obj=rpc.Create(material_instance,pipeline);
if(!rpc.SetVBO(VAN::Position, VF_V2F, position_data))return(false);
for(uint i=0;i<DRAW_OBJECT_COUNT;i++)
{
render_obj[i].r=rpc.Create(render_obj[i].mi,pipeline);
//if(!render_obj)
// return(false);
//
//for(uint i=0;i<6;i++)
//{
// render_root.CreateSubNode(rotate(deg2rad(60*i),Vector3f(0,0,1)),render_obj);
//}
if(!render_obj[i].r)
return(false);
//render_root.RefreshMatrix();
render_root.CreateSubNode(rotate(deg2rad(360/DRAW_OBJECT_COUNT*i),Vector3f(0,0,1)),render_obj[i].r);
}
//render_list->Expend(&render_root);
render_root.RefreshMatrix();
render_list->Expend(&render_root);
return(true);
}

View File

@@ -1,5 +1,5 @@
// third_triangle
// 该范例主要演示使用场景树系统绘制多个三角形并利用RenderList进行排序以及自动合并进行Instance渲染
// AutoInstance
// 该范例主要演示使用RenderList系统绘制多个三角形并利用RenderList进行排序以及自动合并进行Instance渲染
#include"VulkanAppFramework.h"
#include<hgl/math/Math.h>

View File

@@ -1,12 +1,12 @@
#pragma once
#pragma once
#include<hgl/graph/RenderNode.h>
#include<hgl/graph/VKVBOList.h>
VK_NAMESPACE_BEGIN
struct RenderExtraBuffer;
class RenderAssignBuffer;
/**
* ͬһ<EFBFBD><EFBFBD><EFBFBD>ʵĶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ⱦ<EFBFBD>б<EFBFBD>
* 同一材质的对象渲染列表
*/
class MaterialRenderList
{
@@ -19,7 +19,7 @@ class MaterialRenderList
private:
RenderExtraBuffer *extra_buffer;
RenderAssignBuffer *assign_buffer;
struct RenderItem
{
@@ -39,13 +39,14 @@ private:
DataArray<RenderItem> ri_array;
uint ri_count;
void StatMI();
void Stat();
protected:
VBOList * vbo_list;
MaterialInstance * last_mi;
const VIL * last_vil;
Pipeline * last_pipeline;
const VertexInputData * last_vid;
uint last_index;

View File

@@ -23,7 +23,7 @@ namespace hgl
using RenderNodeList=List<RenderNode>;
using MaterialInstanceSets=SortedSets<MaterialInstance *>;
using MaterialInstanceSets=SortedSets<MaterialInstance *>; ///<材质实例集合
}//namespace graph
}//namespace hgl
#endif//HGL_GRAPH_RENDER_NODE_INCLUDE

View File

@@ -6,6 +6,11 @@
#include<hgl/type/String.h>
#include<hgl/graph/VKShaderModuleMap.h>
#include<hgl/graph/VKDescriptorSetType.h>
namespace hgl
{
class ActiveMemoryBlockManager;
}
VK_NAMESPACE_BEGIN
using ShaderStageCreateInfoList=List<VkPipelineShaderStageCreateInfo>;
@@ -30,15 +35,18 @@ class Material
MaterialParameters *mp_array[DESCRIPTOR_SET_TYPE_COUNT];
uint32_t mi_data_bytes; ///<实例数据大小
uint32_t mi_max_count; ///<最大实例数量(注代表一次drawcall大小而不是整个的大小)
uint32_t mi_max_count; ///<实例一次渲染最大数量限制
ActiveMemoryBlockManager *mi_data_manager;
private:
friend class RenderResource;
Material(const AnsiString &);
public:
Material(const AnsiString &);
virtual ~Material();
const UTF8String & GetName ()const{return name;}
@@ -62,12 +70,20 @@ public:
const bool hasSet (const DescriptorSetType &type)const;
const VIL * GetDefaultVIL()const;
VIL * CreateVIL(const VILConfig *format_map=nullptr);
bool Release(VIL *);
const uint GetVILCount();
public:
const bool HasMI ()const{return mi_data_bytes>0;}
const uint32_t GetMIDataBytes ()const{return mi_data_bytes;}
const uint32_t GetMIMaxCount ()const{return mi_max_count;}
void ReleaseMI(int); ///<释放材质实例
void *GetMIData(int); ///<取得指定ID号的材质实例数据访问指针
MaterialInstance *CreateMI(const VILConfig *vil_cfg=nullptr);
};//class Material

View File

@@ -50,6 +50,8 @@ protected:
VIL *vil;
int mi_id;
public:
Material * GetMaterial () {return material;}
@@ -60,11 +62,18 @@ private:
friend class Material;
MaterialInstance(Material *,VIL *);
MaterialInstance(Material *,VIL *,const int);
public:
virtual ~MaterialInstance()=default;
virtual ~MaterialInstance()
{
material->ReleaseMI(mi_id);
}
const int GetMIID ()const{return mi_id;} ///<取得材质实例ID
void * GetMIData (){return material->GetMIData(mi_id);} ///<取得材质实例数据
void WriteMIData (const void *data,const int size); ///<写入材质实例数据
bool BindUBO(const DescriptorSetType &type,const AnsiString &name,DeviceBuffer *ubo,bool dynamic=false);
bool BindSSBO(const DescriptorSetType &type,const AnsiString &name,DeviceBuffer *ubo,bool dynamic=false);

View File

@@ -54,9 +54,15 @@ public:
public:
Pipeline *CreatePipeline(MaterialInstance *, const InlinePipeline &, const Prim &prim,const bool prim_restart=false);
Pipeline *CreatePipeline(MaterialInstance *, const PipelineData *, const Prim &prim,const bool prim_restart=false);
Pipeline *CreatePipeline(MaterialInstance *, const OSString &, const Prim &prim,const bool prim_restart=false);
Pipeline *CreatePipeline(Material *,const VIL *,const PipelineData *, const Prim &,const bool prim_restart=false);
Pipeline *CreatePipeline(Material *,const VIL *,const InlinePipeline &, const Prim &,const bool prim_restart=false);
Pipeline *CreatePipeline(Material *mtl, const PipelineData *, const Prim &,const bool prim_restart=false);
Pipeline *CreatePipeline(Material *mtl, const InlinePipeline &, const Prim &,const bool prim_restart=false);
Pipeline *CreatePipeline(MaterialInstance *, const InlinePipeline &, const Prim &,const bool prim_restart=false);
Pipeline *CreatePipeline(MaterialInstance *, const PipelineData *, const Prim &,const bool prim_restart=false);
Pipeline *CreatePipeline(MaterialInstance *, const OSString &, const Prim &,const bool prim_restart=false);
};//class RenderPass
VK_NAMESPACE_END
#endif//HGL_GRAPH_VULKAN_RENDER_PASS_INCLUDE

View File

@@ -56,7 +56,7 @@ constexpr const ShaderBufferSource SBS_LocalToWorld=
constexpr const char MaterialInstanceStruct[]="MaterialInstance";
constexpr const ShaderBufferSource SBS_MaterialInstanceData=
constexpr const ShaderBufferSource SBS_MaterialInstance=
{
"MaterialInstanceData",
"mtl",

View File

@@ -44,7 +44,8 @@ SET(SCENE_GRAPH_HEADER ${SG_INCLUDE_PATH}/SceneInfo.h
SET(SCENE_GRAPH_SOURCE RenderList.cpp
MaterialRenderList.cpp
RenderExtraBuffer.h
RenderAssignBuffer.h
RenderAssignBuffer.cpp
SceneNode.cpp
SceneOrient.cpp)

View File

@@ -3,8 +3,9 @@
#include<hgl/graph/VKDevice.h>
#include<hgl/graph/VKCommandBuffer.h>
#include<hgl/graph/VKVertexInput.h>
#include<hgl/graph/VKRenderAssign.h>
#include<hgl/util/sort/Sort.h>
#include"RenderExtraBuffer.h"
#include"RenderAssignBuffer.h"
/**
*
@@ -33,10 +34,10 @@ int Comparator<hgl::graph::RenderNode>::compare(const hgl::graph::RenderNode &ob
return off;
}
//比较材质实例
//比较顶点输入格式
{
off=ri_one->GetMaterialInstance()
-ri_two->GetMaterialInstance();
off=ri_one->GetMaterialInstance()->GetVIL()
-ri_two->GetMaterialInstance()->GetVIL();
if(off)
return off;
@@ -60,7 +61,7 @@ MaterialRenderList::MaterialRenderList(GPUDevice *d,Material *m)
device=d;
cmd_buf=nullptr;
mtl=m;
extra_buffer=nullptr;
assign_buffer=new RenderAssignBuffer(d,mtl->GetMIDataBytes());
vbo_list=new VBOList(mtl->GetVertexInput()->GetCount());
}
@@ -68,7 +69,7 @@ MaterialRenderList::MaterialRenderList(GPUDevice *d,Material *m)
MaterialRenderList::~MaterialRenderList()
{
SAFE_CLEAR(vbo_list);
SAFE_CLEAR(extra_buffer)
SAFE_CLEAR(assign_buffer)
}
void MaterialRenderList::Add(Renderable *ri,const Matrix4f &mat)
@@ -90,24 +91,13 @@ void MaterialRenderList::End()
if(node_count<=0)return;
if(!extra_buffer)
extra_buffer=new RenderExtraBuffer;
if(extra_buffer->node_count<node_count)
extra_buffer->NodeAlloc(device,node_count);
if(mtl->HasMI())
StatMI();
Stat();
//写入LocalToWorld数据
extra_buffer->WriteLocalToWorld(rn_list.GetData(),node_count);
const uint mi_count=mi_set.GetCount();
if(mi_count<=0)return;
//if(extra_buffer->mi_count<mi_count)
// extra_buffer->MIAlloc(device,mi_count,);
//extra_buffer->WriteMaterialInstance(rn_list.GetData(),node_count,mi_set);
assign_buffer->WriteNode(rn_list.GetData(),node_count,mi_set);
}
void MaterialRenderList::RenderItem::Set(Renderable *ri)
@@ -117,6 +107,19 @@ void MaterialRenderList::RenderItem::Set(Renderable *ri)
vid =ri->GetVertexInputData();
}
void MaterialRenderList::StatMI()
{
mi_set.Clear();
for(RenderNode &rn:rn_list)
mi_set.Add(rn.ri->GetMaterialInstance());
if(mi_set.GetCount()>mtl->GetMIMaxCount())
{
//超出最大数量了怎么办???
}
}
void MaterialRenderList::Stat()
{
const uint count=rn_list.GetCount();
@@ -125,10 +128,8 @@ void MaterialRenderList::Stat()
ri_array.Clear();
ri_array.Alloc(count);
mi_set.Clear();
RenderItem *ri=ri_array.GetData();
ri_count=1;
ri->first=0;
@@ -136,18 +137,16 @@ void MaterialRenderList::Stat()
ri->Set(rn->ri);
last_pipeline =ri->pipeline;
last_mi =ri->mi;
last_vil =ri->mi->GetVIL();
last_vid =ri->vid;
mi_set.Add(last_mi);
++rn;
for(uint i=1;i<count;i++)
{
{
if(last_pipeline==rn->ri->GetPipeline())
if(last_mi==rn->ri->GetMaterialInstance())
if(last_vid==rn->ri->GetVertexInputData())
if(last_vil==rn->ri->GetMaterialInstance()->GetVIL())
if(last_vid->Comp(rn->ri->GetVertexInputData()))
{
++ri->count;
++rn;
@@ -161,11 +160,8 @@ void MaterialRenderList::Stat()
ri->count=1;
ri->Set(rn->ri);
if(last_mi!=ri->mi)
mi_set.Add(ri->mi);
last_pipeline =ri->pipeline;
last_mi =ri->mi;
last_vil =ri->mi->GetVIL();
last_vid =ri->vid;
++rn;
@@ -176,15 +172,7 @@ void MaterialRenderList::Bind(MaterialInstance *mi)
{
if(!mi)return;
const VIL *vil=mi->GetVIL();
const uint assign_binding_count=vil->GetCount(VertexInputGroup::Assign);
if(assign_binding_count>0)
{
mi->BindUBO(DescriptorSetType::PerFrame,"l2w",extra_buffer->assigns_l2w);
// mi->BindUBO(DescriptorSetType::PerFrame,"Assign",extra_buffer->assigns_mi);
}
assign_buffer->Bind(mi);
cmd_buf->BindDescriptorSets(mi->GetMaterial());
}
@@ -193,7 +181,7 @@ bool MaterialRenderList::Bind(const VertexInputData *vid,const uint ri_index)
{
//binding号都是在VertexInput::CreateVIL时连续紧密排列生成的所以bind时first_binding写0就行了。
const VIL *vil=last_mi->GetVIL();
const VIL *vil=last_vil;
if(vil->GetCount(VertexInputGroup::Basic)!=vid->binding_count)
return(false); //这里基本不太可能因为CreateRenderable时就会检查值是否一样
@@ -233,25 +221,7 @@ bool MaterialRenderList::Bind(const VertexInputData *vid,const uint ri_index)
// }
//}
//if(count<binding_count)//LocalToWorld组由RenderList合成
//{
// const uint l2w_binding_count=vil->GetCount(VertexInputGroup::LocalToWorld);
// if(l2w_binding_count>0) //有变换矩阵信息
// {
// if(l2w_binding_count!=4)
// return(false);
// hgl_cpy(buffer_list+count,extra_buffer->l2w_buffer,4);
// for(uint i=0;i<4;i++)
// buffer_offset[count+i]=ri_index*16; //mat4每列都是rgba32f自然是16字节
// count+=l2w_binding_count;
// }
//}
if(!vbo_list->IsFull())
if(!vbo_list->IsFull()) //Assign组
{
const uint assign_binding_count=vil->GetCount(VertexInputGroup::Assign);
@@ -260,11 +230,10 @@ bool MaterialRenderList::Bind(const VertexInputData *vid,const uint ri_index)
if(assign_binding_count!=1)
return(false);
vbo_list->Add(extra_buffer->assigns_vbo->GetBuffer(),extra_buffer->assigns_vbo_strip*ri_index);
vbo_list->Add(assign_buffer->GetAssignVBO(),ASSIGN_VBO_STRIDE_BYTES*ri_index);
}
}
//if(count!=binding_count)
//{
// //还有没支持的绑定组????
@@ -272,7 +241,6 @@ bool MaterialRenderList::Bind(const VertexInputData *vid,const uint ri_index)
// return(false);
//}
//cmd_buf->BindVBO(0,count,buffer_list,buffer_offset);
cmd_buf->BindVBO(vbo_list);
return(true);
@@ -285,16 +253,15 @@ void MaterialRenderList::Render(RenderItem *ri)
cmd_buf->BindPipeline(ri->pipeline);
last_pipeline=ri->pipeline;
last_mi=nullptr;
last_vid=nullptr;
//这里未来尝试换pipeline同时不换mi/primitive是否需要重新绑定mi/primitive
}
if(last_mi!=ri->mi)
if(last_vil!=ri->mi->GetVIL())
{
Bind(ri->mi);
last_mi=ri->mi;
last_vil=ri->mi->GetVIL();
last_vid=nullptr;
}
@@ -333,7 +300,7 @@ void MaterialRenderList::Render(RenderCmdBuffer *rcb)
RenderItem *ri=ri_array.GetData();
last_pipeline =nullptr;
last_mi =nullptr;
last_vil =nullptr;
last_vid =nullptr;
for(uint i=0;i<ri_count;i++)

View File

@@ -0,0 +1,152 @@
#include"RenderAssignBuffer.h"
#include<hgl/graph/VKVertexAttribBuffer.h>
#include<hgl/graph/VKDevice.h>
#include<hgl/graph/VKMaterialInstance.h>
#include<hgl/graph/RenderNode.h>
#include<hgl/graph/VKRenderable.h>
#include<hgl/graph/VKRenderAssign.h>
#include<hgl/graph/mtl/UBOCommon.h>
VK_NAMESPACE_BEGIN
RenderAssignBuffer::RenderAssignBuffer(GPUDevice *dev,const uint mi_bytes)
{
hgl_zero(*this);
device=dev;
mi_data_bytes=mi_bytes;
ubo_mi=nullptr;
mi_count=0;
}
VkBuffer RenderAssignBuffer::GetAssignVBO()const
{
return vbo_assigns->GetBuffer();
}
void RenderAssignBuffer::Bind(MaterialInstance *mi)const
{
const VIL *vil=mi->GetVIL();
const uint assign_binding_count=vil->GetCount(VertexInputGroup::Assign);
if(assign_binding_count<=0)return;
mi->BindUBO(DescriptorSetType::PerFrame,mtl::SBS_LocalToWorld.name,ubo_l2w);
mi->BindUBO(DescriptorSetType::PerMaterial,mtl::SBS_MaterialInstance.name,ubo_mi);
}
void RenderAssignBuffer::Clear()
{
SAFE_CLEAR(ubo_l2w);
SAFE_CLEAR(ubo_mi);
SAFE_CLEAR(vbo_assigns);
node_count=0;
mi_count=0;
}
void RenderAssignBuffer::Alloc(const uint nc,const uint mc)
{
Clear();
{
node_count=nc;
ubo_l2w=device->CreateUBO(node_count*sizeof(Matrix4f));
}
if(mi_data_bytes>0&&mc>0)
{
mi_count=mc;
ubo_mi=device->CreateUBO(mi_data_bytes*mi_count);
}
vbo_assigns=device->CreateVBO(ASSIGN_VBO_FMT,node_count);
}
void RenderAssignBuffer::WriteNode(RenderNode *render_node,const uint count,const MaterialInstanceSets &mi_set)
{
RenderNode *rn;
Alloc(count,mi_set.GetCount());
if(ubo_mi)
{
uint8 *mip=(uint8 *)(ubo_mi->Map());
for(MaterialInstance *mi:mi_set)
{
memcpy(mip,mi->GetMIData(),mi_data_bytes);
mip+=mi_data_bytes;
}
ubo_mi->Unmap();
}
uint16 *idp=(uint16 *)(vbo_assigns->Map());
{
Matrix4f *tp=(hgl::Matrix4f *)(ubo_l2w->Map());
Matrix4f *l2w=tp;
rn=render_node;
for(uint i=0;i<count;i++)
{
*l2w=rn->local_to_world;
++l2w;
*idp=i;
++idp;
*idp=mi_set.Find(rn->ri->GetMaterialInstance());
++idp;
++rn;
}
ubo_l2w->Unmap();
}
vbo_assigns->Unmap();
}
//void WriteMaterialInstance(RenderNode *render_node,const uint count,const MaterialInstanceSets &mi_set)
//{
// //MaterialInstance ID
// {
// uint8 *tp=(uint8 *)(mi_id->Map());
// for(uint i=0;i<count;i++)
// {
// *tp=mi_set.Find(render_node->ri->GetMaterialInstance());
// ++tp;
// ++render_node;
// }
// mi_id->Unmap();
// }
// //MaterialInstance Data
// {
// //const uint count=mi_set.GetCount();
// //uint8 *tp=(uint8 *)(mi_data_buffer->Map());
// //const MaterialInstance **mi=mi_set.GetData();
// //for(uint i=0;i<count;i++)
// //{
// // memcpy(tp,(*mi)->GetData(),mi_size);
//
// // ++mi;
// // tp+=mi_size;
// //}
// //mi_data_buffer->Unmap();
// }
//}
VK_NAMESPACE_END

View File

@@ -0,0 +1,67 @@
#pragma once
#include<hgl/graph/RenderNode.h>
VK_NAMESPACE_BEGIN
// ubo_range大致分为三档:
//
// 16k: Mali-T系列或更早、Mali-G71为16k
//
// 64k: 大部分手机与PC均为64k
//
// >64k: Intel 核显与 PowerVR 为128MBAMD显卡为4GB可视为随显存无上限。
//
// 我们使用uint8类型在vertex input中保存MaterialInstance ID表示范围0-255。
// 所以MaterialInstance结构容量按16k/64k分为两个档次64字节和256字节
// 如果一定要使用超过16K/64K硬件限制的容量有两种办法
// 一、分多次渲染使用UBO Offset偏移UBO数据区。
// 二、使用SSBO但这样会导致性能下降所以不推荐使用。
// 但我们不解决这个问题
// 我们天然要求将材质实例数据分为两个等级同时要求一次渲染不能超过256种材质实例。
// 所以 UBO Range为16k时实例数据不能超过64字节。UBO Range为64k时实例数据不能超过256字节。
struct RenderNode;
class MaterialInstance;
/*
* 渲染节点额外提供的数据
*/
class RenderAssignBuffer
{
private:
GPUDevice *device;
uint node_count; ///<渲染节点数量
DeviceBuffer *ubo_l2w; ///<Local2World数据
uint32_t mi_data_bytes; ///<材质实例数据字节数
uint32_t mi_count; ///<材质实例数量
DeviceBuffer *ubo_mi; ///<材质实例数据
//Assign VBO
VBO *vbo_assigns; ///<RG16UI格式的VertexInputStream,,,,X:L2W ID,Y:MI ID
private:
void Alloc(const uint nc,const uint mc);
void Clear();
public:
VkBuffer GetAssignVBO()const;
void Bind(MaterialInstance *)const;
public:
RenderAssignBuffer(GPUDevice *dev,const uint32_t mi_bytes);
~RenderAssignBuffer(){Clear();}
void WriteNode(RenderNode *render_node,const uint count,const MaterialInstanceSets &mi_set);
};//struct RenderAssignBuffer
VK_NAMESPACE_END

View File

@@ -1,209 +0,0 @@
#pragma once
#include<hgl/graph/VKVertexAttribBuffer.h>
VK_NAMESPACE_BEGIN
// ubo_range大致分为三档:
//
// 16k: Mali-T系列或更早、Mali-G71为16k
//
// 64k: 大部分手机与PC均为64k
//
// >64k: Intel 核显与 PowerVR 为128MBAMD显卡为4GB可视为随显存无上限。
//
// 我们使用uint8类型在vertex input中保存MaterialInstance ID表示范围0-255。
// 所以MaterialInstance结构容量按16k/64k分为两个档次64字节和256字节
// 如果一定要使用超过16K/64K硬件限制的容量有两种办法
// 一、分多次渲染使用UBO Offset偏移UBO数据区。
// 二、使用SSBO但这样会导致性能下降所以不推荐使用。
// 但我们不解决这个问题
// 我们天然要求将材质实例数据分为两个等级同时要求一次渲染不能超过256种材质实例。
// 所以 UBO Range为16k时实例数据不能超过64字节。UBO Range为64k时实例数据不能超过256字节。
/*
* 渲染节点额外提供的数据
*/
struct RenderExtraBuffer
{
uint node_count; ///<渲染节点数量
// uint mi_count; ///<材质实例数量
//uint mi_size; ///<单个材质实例数量长度
//DeviceBuffer *mi_data_buffer; ///<材质实例数据UBO/SSBO
//VBO *mi_id;
//VkBuffer mi_id_buffer;
// VBO *bone_id,*bone_weight;
// VkBuffer bone_id_buffer,bone_weight_buffer;
VBO *l2w_vbo[4];
VkBuffer l2w_buffer[4];
//------------------------------------------------------------
//Assign UBO
DeviceBuffer *assigns_l2w;
DeviceBuffer *assigns_mi;
//Assign VBO
VBO *assigns_vbo; ///<RG16UI格式的VertexInputStream,,,,X:L2W ID,Y:MI ID
const uint assigns_vbo_strip=2; ///<Assign VBO的每个节点的字节数
public:
RenderExtraBuffer()
{
hgl_zero(*this);
}
~RenderExtraBuffer()
{
Clear();
}
void ClearNode()
{
SAFE_CLEAR(assigns_l2w);
SAFE_CLEAR(assigns_mi);
SAFE_CLEAR(assigns_vbo);
SAFE_CLEAR(l2w_vbo[0])
SAFE_CLEAR(l2w_vbo[1])
SAFE_CLEAR(l2w_vbo[2])
SAFE_CLEAR(l2w_vbo[3])
node_count=0;
}
//void ClearMI()
//{
// SAFE_CLEAR(mi_id)
// SAFE_CLEAR(mi_data_buffer);
// mi_count=0;
// mi_size=0;
//}
void Clear()
{
ClearNode();
// ClearMI();
// SAFE_CLEAR(bone_id)
// SAFE_CLEAR(bone_weight)
}
void NodeAlloc(GPUDevice *dev,const uint c)
{
ClearNode();
node_count=power_to_2(c);
for(uint i=0;i<4;i++)
{
l2w_vbo[i]=dev->CreateVBO(VF_V4F,node_count);
l2w_buffer[i]=l2w_vbo[i]->GetBuffer();
}
assigns_l2w=dev->CreateUBO(node_count*sizeof(Matrix4f));
//assigns_mi=dev->CreateUBO(node_count*sizeof(uint8));
assigns_vbo=dev->CreateVBO(VF_V1U16,node_count);
}
//void MIAlloc(GPUDevice *dev,const uint c,const uint mis)
//{
// ClearMI();
// if(c<=0||mi_size<=0)return;
//
// mi_count=power_to_2(c);
// mi_size=mis;
// mi_id=dev->CreateVBO(VF_V1U8,mi_count);
// mi_id_buffer=mi_id->GetBuffer();
// mi_data_buffer=dev->CreateUBO(mi_count*mi_size);
//}
void WriteLocalToWorld(RenderNode *render_node,const uint count)
{
RenderNode *rn;
//old l2w in vertex input stream
{
glm::vec4 *tp;
for(uint col=0;col<4;col++)
{
tp=(glm::vec4 *)(l2w_vbo[col]->Map());
rn=render_node;
for(uint i=0;i<count;i++)
{
*tp=rn->local_to_world[col];
++tp;
++rn;
}
l2w_vbo[col]->Unmap();
}
}
//new l2w array in ubo
{
Matrix4f *tp=(hgl::Matrix4f *)(assigns_l2w->Map());
uint16 *idp=(uint16 *)(assigns_vbo->Map());
rn=render_node;
for(uint i=0;i<count;i++)
{
*tp=rn->local_to_world;
++tp;
*idp=i;
++idp;
++rn;
}
assigns_vbo->Unmap();
assigns_l2w->Unmap();
}
}
//void WriteMaterialInstance(RenderNode *render_node,const uint count,const MaterialInstanceSets &mi_set)
//{
// //MaterialInstance ID
// {
// uint8 *tp=(uint8 *)(mi_id->Map());
// for(uint i=0;i<count;i++)
// {
// *tp=mi_set.Find(render_node->ri->GetMaterialInstance());
// ++tp;
// ++render_node;
// }
// mi_id->Unmap();
// }
// //MaterialInstance Data
// {
// //const uint count=mi_set.GetCount();
// //uint8 *tp=(uint8 *)(mi_data_buffer->Map());
// //const MaterialInstance **mi=mi_set.GetData();
// //for(uint i=0;i<count;i++)
// //{
// // memcpy(tp,(*mi)->GetData(),mi_size);
//
// // ++mi;
// // tp+=mi_size;
// //}
// //mi_data_buffer->Unmap();
// }
//}
};//struct RenderExtraBuffer
VK_NAMESPACE_END

View File

@@ -1,26 +1,58 @@
# 静态渲染管理
## 建立静态渲染管理的意义是什么?
## 静态渲染的意义是什么?
静态渲染管理中的“静态”并不是指在场景中静止不动的所有物件,也不是指永远不会增加或删除的物件
而是说大部分时间,都会出现在场景中的物件。
静态渲染管理中的“静态”并不是指在场景中静止不动的所有物件,而是说大部分时间都会出现在场景中的物件。它包含地形、花草树木、房屋、常见人物,武器装备等等。如果归划好,可以将绝大部分的物件都划入静态渲染中
它的意义为的是所有添加进管理器的模型原始资源,都会一直存在。与它们本身是否显示在画面中,并无关联。为的是避开对显存资源的动态调配。
在静态渲染管理器中的所有模型,会根据顶点数据格式(Vertex Input Format)分类。每种格式所有模型共用一个大的顶点缓冲对象(Vertex Buffer Object)以达到在渲染时渲染不同模型不会切换VBO的效果并进一步达成一个格式一次Drawcall全部画的极致效果。
在静态渲染管理器中的所有模型,会根据顶点数据格式(Vertex Input Format)分类。每种格式所有模型共用一套超大VBO(Vertex Buffer Object)以达到在渲染时渲染不同模型不会切换VBO的效果并进一步达成一个格式一次Drawcall全部画完”的极致效果。
## 定义
## 材质的定义
1.Material 材质可以简单理解为是Shader的包装。
2.Vertex Input Layout 顶点输入布局指的是在渲染中Material所需的顶点输入数据格式
但需要注意的是VertexInputLayout与Material并无从属关系。
一个Material可能会有多个VertexInputLayout的版本,不同具体格式的数据输入.
多个Material也可能会共用一个VertexInputLayout,比如为某个模型设定的不同画质渲染,它们shader不同但是共用同一套模型数据。
3.Material Instance 材质实例是指同一材质下,不同的参数配置或不同的顶点输入格式。
2.Material Instance 材质实例是指同一材质下,不同的参数配置
## 我们需要做什么?
1.在Shader中建立两个UBO或SSBO
```glsl
//一个用于存所有Local to World矩阵的数组
#define MI_MAX_COUNT (UBORange/sizeof(mat4))
layout(set=?,binding=?) uniform LocalToWorldData
{
mat4 mats[L2W_MAX_COUNT];
}l2w;
```
```glsl
//一个用于存所有MaterialInstance数据的数组
#define MI_MAX_COUNT (UBORange/sizeof(MaterialInstance))
layout(set=?,binding=?) uniform MaterialInstanceData
{
MaterialInstance mi_array[MI_MAX_COUNT];
}mi;
```
2.建立一个RG8UI或RG16UI的Vertex Input Stream,用于保存访问LocalToWorld/MaterialInstance的索引
```glsl
layout(location=?) in uvec2 Assign; //Local To World矩阵ID与材质ID输入数据流
mat4 GetLocalToWorld()
{
return l2w.mats[Assign.x];
}
MaterialInstance GetMaterialInstance()
{
return mi.mi_array[Assign.y];
}
```

View File

@@ -12,6 +12,8 @@ const VkDeviceSize GPUDevice::GetSSBORange (){return attr->physical_device->Get
bool GPUDevice::CreateBuffer(DeviceBufferData *buf,VkBufferUsageFlags buf_usage,VkDeviceSize range,VkDeviceSize size,const void *data,SharingMode sharing_mode)
{
if(size<=0)return(false);
BufferCreateInfo buf_info;
buf_info.usage = buf_usage;
@@ -55,6 +57,8 @@ bool GPUDevice::CreateBuffer(DeviceBufferData *buf,VkBufferUsageFlags buf_usage,
VBO *GPUDevice::CreateVBO(VkFormat format,uint32_t count,const void *data,SharingMode sharing_mode)
{
if(count==0)return(nullptr);
const uint32_t stride=GetStrideByFormat(format);
if(stride==0)
@@ -75,6 +79,8 @@ VBO *GPUDevice::CreateVBO(VkFormat format,uint32_t count,const void *data,Sharin
IndexBuffer *GPUDevice::CreateIBO(IndexType index_type,uint32_t count,const void *data,SharingMode sharing_mode)
{
if(count==0)return(nullptr);
uint32_t stride;
if(index_type==IndexType::U8 )stride=1;else
@@ -94,6 +100,8 @@ IndexBuffer *GPUDevice::CreateIBO(IndexType index_type,uint32_t count,const void
DeviceBuffer *GPUDevice::CreateBuffer(VkBufferUsageFlags buf_usage,VkDeviceSize range,VkDeviceSize size,const void *data,SharingMode sharing_mode)
{
if(size<=0)return(nullptr);
DeviceBufferData buf;
if(!CreateBuffer(&buf,buf_usage,range,size,data,sharing_mode))

View File

@@ -3,7 +3,12 @@
#include<hgl/graph/VKMaterialDescriptorManager.h>
#include<hgl/graph/VKVertexInput.h>
#include"VKPipelineLayoutData.h"
#include<hgl/type/ActiveMemoryBlockManager.h>
VK_NAMESPACE_BEGIN
void ReleaseVertexInput(VertexInput *vi);
Material::Material(const AnsiString &n)
{
name=n;
@@ -16,21 +21,20 @@ Material::Material(const AnsiString &n)
hgl_zero(mp_array);
mi_data_bytes=0;
mi_max_count=0;
mi_data_manager=nullptr;
}
Material::~Material()
{
SAFE_CLEAR(vertex_input);
SAFE_CLEAR(mi_data_manager);
ReleaseVertexInput(vertex_input);
delete shader_maps; //不用SAFE_CLEAR是因为这个一定会有
SAFE_CLEAR(desc_manager);
SAFE_CLEAR(pipeline_layout_data);
for(int i=0;i<DESCRIPTOR_SET_TYPE_COUNT;i++)
SAFE_CLEAR(mp_array[i]);
mi_data_bytes=0;
mi_max_count=0;
}
const VkPipelineLayout Material::GetPipelineLayout()const
@@ -43,6 +47,11 @@ const bool Material::hasSet(const DescriptorSetType &dst)const
return desc_manager->hasSet(dst);
}
const VIL *Material::GetDefaultVIL()const
{
return vertex_input->GetDefaultVIL();
}
VIL *Material::CreateVIL(const VILConfig *format_map)
{
return vertex_input->CreateVIL(format_map);

View File

@@ -2,6 +2,7 @@
#include<hgl/graph/VKMaterialInstance.h>
#include<hgl/graph/VKMaterialParameters.h>
#include<hgl/graph/VKShaderModule.h>
#include<hgl/type/ActiveMemoryBlockManager.h>
VK_NAMESPACE_BEGIN
MaterialInstance *Material::CreateMI(const VILConfig *vil_cfg)
@@ -10,14 +11,48 @@ MaterialInstance *Material::CreateMI(const VILConfig *vil_cfg)
if(!vil)return(nullptr);
return(new MaterialInstance(this,vil));
int mi_id=-1;
if(mi_data_manager)
mi_data_manager->GetOrCreate(&mi_id,1);
else
mi_id=-1;
return(new MaterialInstance(this,vil,mi_id));
}
MaterialInstance::MaterialInstance(Material *mtl,VIL *v)
void Material::ReleaseMI(int mi_id)
{
if(mi_id<0||!mi_data_manager)return;
mi_data_manager->Release(&mi_id,1);
}
void *Material::GetMIData(int id)
{
if(!mi_data_manager)
return(nullptr);
return mi_data_manager->GetData(id);
}
void MaterialInstance::WriteMIData(const void *data,const int size)
{
if(!data||size<=0||size>material->GetMIDataBytes())return;
void *tp=GetMIData();
if(tp)
memcpy(tp,data,size);
}
MaterialInstance::MaterialInstance(Material *mtl,VIL *v,const int id)
{
material=mtl;
vil=v;
mi_id=id;
}
bool MaterialInstance::BindUBO(const DescriptorSetType &type,const AnsiString &name,DeviceBuffer *ubo,bool dynamic)

View File

@@ -56,33 +56,14 @@ Pipeline *RenderPass::CreatePipeline(PipelineData *pd,const ShaderStageCreateInf
return(new Pipeline(device,graphicsPipeline,pd));
}
Pipeline *RenderPass::CreatePipeline(MaterialInstance *mi,const InlinePipeline &ip,const Prim &prim,const bool prim_restart)
Pipeline *RenderPass::CreatePipeline(Material *mtl,const VIL *vil,const PipelineData *cpd,const Prim &prim,const bool prim_restart)
{
if(!mi)return(nullptr);
Material *mtl=mi->GetMaterial();
const PipelineData *cpd=GetPipelineData(ip);
PipelineData *pd=new PipelineData(cpd);
pd->SetPrim(prim,prim_restart);
Pipeline *p=CreatePipeline(pd,mtl->GetStageList(),mtl->GetPipelineLayout(),mi->GetVIL());
if(p)
pipeline_list.Add(p);
return p;
}
Pipeline *RenderPass::CreatePipeline(MaterialInstance *mi,const PipelineData *cpd,const Prim &prim,const bool prim_restart)
{
Material *mtl=mi->GetMaterial();
PipelineData *pd=new PipelineData(cpd);
pd->SetPrim(prim,prim_restart);
Pipeline *p=CreatePipeline(pd,mtl->GetStageList(),mtl->GetPipelineLayout(),mi->GetVIL());
Pipeline *p=CreatePipeline(pd,mtl->GetStageList(),mtl->GetPipelineLayout(),vil);
if(p)
pipeline_list.Add(p);
@@ -90,6 +71,35 @@ Pipeline *RenderPass::CreatePipeline(MaterialInstance *mi,const PipelineData *cp
return(p);
}
Pipeline *RenderPass::CreatePipeline(Material *mtl,const VIL *vil,const InlinePipeline &ip,const Prim &prim,const bool prim_restart)
{
if(!mtl)return(nullptr);
return CreatePipeline(mtl,vil,GetPipelineData(ip),prim,prim_restart);
}
Pipeline *RenderPass::CreatePipeline(Material *mtl,const PipelineData *pd, const Prim &prim,const bool prim_restart)
{
return CreatePipeline(mtl,mtl->GetDefaultVIL(),pd,prim,prim_restart);
}
Pipeline *RenderPass::CreatePipeline(Material *mtl,const InlinePipeline &ip, const Prim &prim,const bool prim_restart)
{
return CreatePipeline(mtl,mtl->GetDefaultVIL(),ip,prim,prim_restart);
}
Pipeline *RenderPass::CreatePipeline(MaterialInstance *mi,const InlinePipeline &ip,const Prim &prim,const bool prim_restart)
{
if(!mi)return(nullptr);
return CreatePipeline(mi->GetMaterial(),mi->GetVIL(),ip,prim,prim_restart);
}
Pipeline *RenderPass::CreatePipeline(MaterialInstance *mi,const PipelineData *cpd,const Prim &prim,const bool prim_restart)
{
return CreatePipeline(mi->GetMaterial(),mi->GetVIL(),cpd,prim,prim_restart);
}
Pipeline *RenderPass::CreatePipeline(MaterialInstance *mi,const OSString &pipeline_filename,const Prim &prim,const bool prim_restart)
{
const PipelineData *pd=GetPipelineData(pipeline_filename);

View File

@@ -10,6 +10,7 @@
#include<hgl/io/ConstBufferReader.h>
#include<hgl/shadergen/MaterialCreateInfo.h>
#include<hgl/shadergen/ShaderDescriptorInfo.h>
#include<hgl/type/ActiveMemoryBlockManager.h>
VK_NAMESPACE_BEGIN
@@ -123,7 +124,7 @@ Material *RenderResource::CreateMaterial(const mtl::MaterialCreateInfo *mci)
ShaderCreateInfoVertex *vert=mci->GetVS();
if(vert)
mtl->vertex_input=new VertexInput(vert->sdm->GetShaderStageIO().input);
mtl->vertex_input=GetVertexInput(vert->sdm->GetShaderStageIO().input);
}
{
@@ -147,6 +148,11 @@ Material *RenderResource::CreateMaterial(const mtl::MaterialCreateInfo *mci)
mtl->mi_data_bytes =mci->GetMIDataBytes();
mtl->mi_max_count =mci->GetMIMaxCount();
if(mtl->mi_data_bytes>0)
{
mtl->mi_data_manager=new ActiveMemoryBlockManager(mtl->mi_data_bytes);
}
Add(mtl);
material_by_name.Add(mtl_name,mtl);

View File

@@ -27,10 +27,7 @@ MaterialCreateInfo::MaterialCreateInfo(const MaterialCreateConfig *mc)
}
{
l2w_max_count=ubo_range/sizeof(Matrix4f);
if(l2w_max_count>HGL_U16_MAX)
l2w_max_count=HGL_U16_MAX;
l2w_max_count=hgl_min<uint32_t>(ubo_range/sizeof(Matrix4f),HGL_U16_MAX);
l2w_shader_stage=0;
l2w_ubo=nullptr;
@@ -158,20 +155,15 @@ bool MaterialCreateInfo::SetMaterialInstance(const AnsiString &glsl_codes,const
if(data_bytes>0)
mi_codes=glsl_codes;
{
mi_max_count=ubo_range/data_bytes;
if(mi_max_count>HGL_U16_MAX) //我们使用uint16传递材质实例ID所以最大数量为65535。未来如考虑使用更多需综合考虑
mi_max_count=HGL_U16_MAX;
}
mi_max_count=hgl_min<uint32_t>(ubo_range/data_bytes,HGL_U16_MAX);
mdi.AddStruct(MaterialInstanceStruct,mi_codes);
mdi.AddStruct(SBS_MaterialInstanceData);
mdi.AddStruct(SBS_MaterialInstance);
mi_ubo=new UBODescriptor();
mi_ubo->type=SBS_MaterialInstanceData.struct_name;
hgl::strcpy(mi_ubo->name,DESCRIPTOR_NAME_MAX_LENGTH,SBS_MaterialInstanceData.name);
mi_ubo->type=SBS_MaterialInstance.struct_name;
hgl::strcpy(mi_ubo->name,DESCRIPTOR_NAME_MAX_LENGTH,SBS_MaterialInstance.name);
mi_ubo->stage_flag=shader_stage_flag_bits;
mdi.AddUBO(shader_stage_flag_bits,DescriptorSetType::PerMaterial,mi_ubo);

View File

@@ -2,6 +2,7 @@
#include<hgl/shadergen/ShaderDescriptorInfo.h>
#include<hgl/graph/VertexAttrib.h>
#include<hgl/graph/VKShaderStage.h>
#include<hgl/graph/VKRenderAssign.h>
#include"GLSLCompiler.h"
#include"common/MFCommon.h"
@@ -39,9 +40,10 @@ void ShaderCreateInfoVertex::AddJoint()
void ShaderCreateInfoVertex::AddAssign()
{
char name[]="Assign";
AddInput(VAT_UINT,name,VK_VERTEX_INPUT_RATE_INSTANCE,VertexInputGroup::Assign);
AddInput( ASSIGN_VAT_FMT,
ASSIGN_VIS_NAME,
VK_VERTEX_INPUT_RATE_INSTANCE,
VertexInputGroup::Assign);
AddFunction(mtl::func::GetLocalToWorld);
}