Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 82 additions & 4 deletions source/runtime/render/scene/CpuScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,40 @@

#include "LogicalComponents.h"
#include "LogicalScene.h"
#include "log/LogSystem.h"
#include "config/ConfigManager.h"
#include "scene/LogicalComponents.h"
#include "shaderheaders/shared/scene/SharedSceneStruct.h"
#include <entt/entt.hpp>
#include <sstream>

namespace Moer {

CpuScene::CpuScene(ecs::LogicalScene& m_logical_scene) : m_logical_scene(m_logical_scene) {
CpuScene::CpuScene(ecs::LogicalScene& m_logical_scene) :
m_logical_scene(m_logical_scene),
m_frame_data(ConfigManager::GetInstance().GetConfig().engine.rhi.max_frame_in_flight) {
/**
* 注意初始化顺序:
* - Materials必须在Meshes之前初始化,因为Mesh需要Material ID
*/
InitializeLights();
InitializeMaterials();
InitializeMeshes();

SetupObservers();
}

void CpuScene::Update() {
auto& r = m_logical_scene.r();

UpdateLights();
UpdateMaterials();
UpdateMeshes();

r.clear<ecs::CTagDirtyLight>();
r.clear<ecs::CTagDirtyMaterial>();
r.clear<ecs::CTagDirtyTransform>();

m_current_frame_idx = (m_current_frame_idx + 1) % m_frame_data.size();
}

uint CpuScene::GetPrimitiveId(entt::entity primitive_entt) const {
Expand Down Expand Up @@ -124,7 +137,50 @@ void CpuScene::InitializeLights() {
}

void CpuScene::UpdateLights() {
// TODO
auto& r = m_logical_scene.r();

// 查询所有被标记为 dirty 的 Light 实体
auto view = r.view<const ecs::CTagDirtyLight, const ecs::CLight>();
view.each([&](const auto entity, const ecs::CLight& c_light) {
auto light_id_it = m_map_light_entity_to_id.find(entity);
if (light_id_it == m_map_light_entity_to_id.end()) {
LOG_ERROR("The light to update was not initialized. Adding new lights is not supported yet.");
return;
}

uint light_id = light_id_it->second;
GLight light{};

if (r.all_of<ecs::CLightDirectional>(entity)) {
const auto& c_light = r.get<ecs::CLightDirectional>(entity);
light.color = c_light.color;
light.intensity = c_light.intensity;
light.type = static_cast<uint>(ELightType::Directional);
light.direction = m_logical_scene.GetDirectionalLightDirection(entity);
} else if (r.all_of<ecs::CLightPoint>(entity)) {
const auto& c_light = r.get<ecs::CLightPoint>(entity);
light.color = c_light.color;
light.intensity = c_light.intensity;
light.position = m_logical_scene.GetPointLightPosition(entity);
light.type = static_cast<uint>(ELightType::Point);
} else if (r.all_of<ecs::CLightAmbient>(entity)) {
const auto& c_light = r.get<ecs::CLightAmbient>(entity);
light.color = c_light.color;
light.intensity = c_light.intensity;
light.type = static_cast<uint>(ELightType::Ambient);
} else if (r.all_of<ecs::CLightSpot>(entity)) {
// TODO: spot light 更新待实现
LOG_ERROR("CLightSpot is not implemented yet");
return;
} else if (r.all_of<ecs::CLightEnvironment>(entity)) {
// TODO: environment light 更新待实现
LOG_ERROR("CLightEnvironment is not implemented yet");
return;
}

GetCurrentFrameData().lights.emplace_back(light);
GetCurrentFrameData().dirty_light_indices.emplace_back(light_id);
});
}

void CpuScene::InitializeMaterials() {
Expand Down Expand Up @@ -170,7 +226,29 @@ void CpuScene::InitializeMaterials() {
}

void CpuScene::UpdateMaterials() {
// TODO
auto& r = m_logical_scene.r();

auto view = r.view<const ecs::CTagDirtyMaterial, const ecs::CMaterial>();
view.each([&](const auto entity, const ecs::CMaterial& c_material) {
auto mat_id_it = m_map_material_entity_to_id.find(entity);
if (mat_id_it == m_map_material_entity_to_id.end()) {
LOG_ERROR(
"The material to update was not initialized. Adding new materials is not supported yet."
);
return;
}

GMaterial g_material{};
g_material.albedo_factor = c_material.albedo_factor;
g_material.emissive_factor = c_material.emissive_factor;
g_material.metallic_factor = c_material.metallic_factor;
g_material.roughness_factor = c_material.roughness_factor;
g_material.alpha_mode = static_cast<uint8>(c_material.alpha_mode);
g_material.alpha_cutoff = c_material.alpha_cutoff;

GetCurrentFrameData().materials.emplace_back(g_material);
GetCurrentFrameData().dirty_material_indices.emplace_back(mat_id_it->second);
});
}

void CpuScene::InitializeMeshes() {
Expand Down
30 changes: 28 additions & 2 deletions source/runtime/render/scene/CpuScene.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ class GpuScene;
* - 存储所有准备上传到GPU的场景数据;
* - 实现所有 LogicalScene -> CpuScene 的逻辑
*
* TODO: LogicalScene数据变更时,增量更新CpuScene数据
* 考虑使用 事件队列 或 观察者模式
* 增量更新通过CTagDirty实现:
* - 当CLight/CMaterial/CTransform被修改时,观察者回调会添加CTagDirty标签
* - UpdateLights/UpdateMaterials/UpdateMeshes通过view过滤出有CTagDirty的实体进行处理
* - 处理完毕后清除CTagDirty标签
*/
class RENDER_API CpuScene {

Expand All @@ -43,6 +45,20 @@ class RENDER_API CpuScene {
CpuScene(const CpuScene&) = delete;
CpuScene& operator=(const CpuScene&) = delete;

// 每帧更新数据的缓冲,包含所有 Lights、Materials、Instances 的完整数据,以及增量更新的索引列表
struct FrameData {
Array<GLight> lights;
Array<GMaterial> materials;
Array<GInstance> instances;

Array<uint> dirty_light_indices;
Array<uint> dirty_material_indices;
Array<uint> dirty_instance_indices;
};

FrameData& GetCurrentFrameData() { return m_frame_data[m_current_frame_idx]; }
const FrameData& GetCurrentFrameData() const { return m_frame_data[m_current_frame_idx]; }

void Update();

/**
Expand Down Expand Up @@ -91,6 +107,16 @@ class RENDER_API CpuScene {
ecs::LogicalScene& m_logical_scene;

private:
// frame data 的大小与 frame_in_flight 一直
Array<FrameData> m_frame_data{};
size_t m_current_frame_idx = 0;

/**
* 设置观察者,监听 LogicalScene 中 CLight/CMaterial/CTransform 的修改
* - 当被修改时,观察者回调会添加 CTagDirty 标签
*/
void SetupObservers();

/**
* 下面的内容分为3类:数据、map缓存、逻辑
* - 数据:存储最终上传到Gpu的数据
Expand Down
151 changes: 108 additions & 43 deletions source/runtime/render/scene/GpuScene.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "GpuScene.h"

#include "CpuScene.h"
#include "log/LogSystem.h"
#include "config/ConfigManager.h"
#include "rhi/RHI.h"
#include "rhi/RHICommand.h"
#include "rhi/RHICommon.h"
Expand All @@ -26,6 +26,7 @@ namespace Moer::Render {
GpuScene::GpuScene(CpuScene& cpu_scene, BindlessArrayRef bindless_array) :
m_logical_scene(cpu_scene.m_logical_scene),
m_cpu_scene(cpu_scene),
m_frame_in_flight(ConfigManager::GetInstance().GetConfig().engine.rhi.max_frame_in_flight),
m_bindless_array(bindless_array) {

m_res = Res{};
Expand Down Expand Up @@ -124,17 +125,23 @@ GpuScene::GpuScene(CpuScene& cpu_scene, BindlessArrayRef bindless_array) :
* 此处按照 Res 中顺序进行创建
*/

m_res.light_buf.buf = device.CreateBuffer<byte>(
"GpuScene::LightBuffer",
m_cpu_scene.m_light_buf.size() * sizeof(GLight),
EBufferUsageFlags::UNORDERED_ACCESS
);
m_res.light_bufs.resize(m_frame_in_flight);
for (uint i = 0; i < m_frame_in_flight; ++i) {
m_res.light_bufs[i].buf = device.CreateBuffer<byte>(
std::format("GpuScene::LightBuffer_{}", i),
m_cpu_scene.m_light_buf.size() * sizeof(GLight),
EBufferUsageFlags::UNORDERED_ACCESS
);
}

m_res.material_buf.buf = device.CreateBuffer<byte>(
"GpuScene::MaterialBuffer",
m_cpu_scene.m_material_buf.size() * sizeof(GMaterial),
EBufferUsageFlags::UNORDERED_ACCESS
);
m_res.material_bufs.resize(m_frame_in_flight);
for (uint i = 0; i < m_frame_in_flight; ++i) {
m_res.material_bufs[i].buf = device.CreateBuffer<byte>(
std::format("GpuScene::MaterialBuffer_{}", i),
m_cpu_scene.m_material_buf.size() * sizeof(GMaterial),
EBufferUsageFlags::UNORDERED_ACCESS
);
}

// 这里不设置为byte,是为了GeometryPass中可以直接获取 命令的数量(cpu count)、DrawIndexedCmdData的stride
m_res.draw_cmd_buf.buf = device.CreateBuffer<Render::DrawIndexedCmdData>(
Expand All @@ -149,11 +156,14 @@ GpuScene::GpuScene(CpuScene& cpu_scene, BindlessArrayRef bindless_array) :
EBufferUsageFlags::UNORDERED_ACCESS
);

m_res.instance_buf.buf = device.CreateBuffer<byte>(
"GpuScene::InstanceBuffer",
m_cpu_scene.m_instance_buf.size() * sizeof(GInstance),
EBufferUsageFlags::UNORDERED_ACCESS
);
m_res.instance_bufs.resize(m_frame_in_flight);
for (uint i = 0; i < m_frame_in_flight; ++i) {
m_res.instance_bufs[i].buf = device.CreateBuffer<byte>(
"GpuScene::InstanceBuffer",
m_cpu_scene.m_instance_buf.size() * sizeof(GInstance),
EBufferUsageFlags::UNORDERED_ACCESS
);
}

m_res.position_buf.buf = device.CreateBuffer<byte>(
"GpuScene::PositionMegaBuffer",
Expand Down Expand Up @@ -191,21 +201,26 @@ GpuScene::GpuScene(CpuScene& cpu_scene, BindlessArrayRef bindless_array) :
* 此处按照 Res 中顺序进行上传
*/

m_pending_cmd_lists.copy_queue_cmd_list.CopyFrom(
std::span<byte>(
(byte*)m_cpu_scene.m_light_buf.data(), m_cpu_scene.m_light_buf.size() * sizeof(GLight)
),
m_res.light_buf.buf->GetView(),
"CopyFrom GpuScene::LightBuffer"
);
for (uint i = 0; i < m_frame_in_flight; ++i) {
m_pending_cmd_lists.copy_queue_cmd_list.CopyFrom(
std::span<byte>(
(byte*)m_cpu_scene.m_light_buf.data(), m_cpu_scene.m_light_buf.size() * sizeof(GLight)
),
m_res.light_bufs[i].buf->GetView(),
"CopyFrom GpuScene::LightBuffer"
);
}

m_pending_cmd_lists.copy_queue_cmd_list.CopyFrom(
std::span<byte>(
(byte*)m_cpu_scene.m_material_buf.data(), m_cpu_scene.m_material_buf.size() * sizeof(GMaterial)
),
m_res.material_buf.buf->GetView(),
"CopyFrom GpuScene::MaterialBuffer"
);
for (uint i = 0; i < m_frame_in_flight; ++i) {
m_pending_cmd_lists.copy_queue_cmd_list.CopyFrom(
std::span<byte>(
(byte*)m_cpu_scene.m_material_buf.data(),
m_cpu_scene.m_material_buf.size() * sizeof(GMaterial)
),
m_res.material_bufs[i].buf->GetView(),
"CopyFrom GpuScene::MaterialBuffer"
);
}

m_pending_cmd_lists.copy_queue_cmd_list.CopyFrom(
std::span<byte>(
Expand All @@ -224,13 +239,16 @@ GpuScene::GpuScene(CpuScene& cpu_scene, BindlessArrayRef bindless_array) :
"CopyFrom GpuScene::PrimitiveBuffer"
);

m_pending_cmd_lists.copy_queue_cmd_list.CopyFrom(
std::span<byte>(
(byte*)m_cpu_scene.m_instance_buf.data(), m_cpu_scene.m_instance_buf.size() * sizeof(GInstance)
),
m_res.instance_buf.buf->GetView(),
"CopyFrom GpuScene::InstanceBuffer"
);
for (uint i = 0; i < m_frame_in_flight; ++i) {
m_pending_cmd_lists.copy_queue_cmd_list.CopyFrom(
std::span<byte>(
(byte*)m_cpu_scene.m_instance_buf.data(),
m_cpu_scene.m_instance_buf.size() * sizeof(GInstance)
),
m_res.instance_bufs[i].buf->GetView(),
"CopyFrom GpuScene::InstanceBuffer"
);
}

m_pending_cmd_lists.copy_queue_cmd_list.CopyFrom(
std::span<byte>(
Expand Down Expand Up @@ -286,18 +304,21 @@ GpuScene::GpuScene(CpuScene& cpu_scene, BindlessArrayRef bindless_array) :
*/

Array<BufferWithHandle*> buffers = {
&m_res.light_buf,
&m_res.material_buf,
&m_res.draw_cmd_buf,
&m_res.primitive_buf,
&m_res.instance_buf,
&m_res.position_buf,
&m_res.packed_normal_buf,
&m_res.packed_tangent_buf,
&m_res.texcoord0_buf,
&m_res.index_buf,
};

for (uint i = 0; i < m_frame_in_flight; ++i) {
buffers.push_back(&m_res.light_bufs[i]);
buffers.push_back(&m_res.material_bufs[i]);
buffers.push_back(&m_res.instance_bufs[i]);
}

for (auto& buf_with_hdl_ptr : buffers) {
BufferWithHandle& buf_with_hdl = *buf_with_hdl_ptr;

Expand Down Expand Up @@ -362,11 +383,55 @@ GpuScene::GpuScene(CpuScene& cpu_scene, BindlessArrayRef bindless_array) :
}

void GpuScene::Update(const ecs::LogicalScene& m_logical_scene, CpuScene& m_cpu_scene) {
auto& device = RenderDevice::Get();
UpdateLights(m_cpu_scene);
UpdateMaterials(m_cpu_scene);
UpdateInstances(m_cpu_scene);

UpdateRaytracingScene(m_pending_cmd_lists.gfx_queue_cmd_list); // gfx_queue交给主线程执行

// TODO: others
m_current_frame_idx = (m_current_frame_idx + 1) % m_frame_in_flight;
}

UpdateRaytracingScene(m_pending_cmd_lists.gfx_queue_cmd_list); // gfx_queue交给主线程执行
void GpuScene::UpdateLights(CpuScene& cpu_scene) {
const auto& frame_data = cpu_scene.GetCurrentFrameData();
auto& cmd_list = m_pending_cmd_lists.copy_queue_cmd_list;
BufferWithHandle& light_buf = m_res.light_bufs[m_current_frame_idx];

for (uint idx : frame_data.dirty_light_indices) {
cmd_list.CopyFrom(
std::span<byte>((byte*)&frame_data.lights[idx], sizeof(GLight)),
light_buf.buf->GetView(idx * sizeof(GLight), sizeof(GLight)),
std::format("UpdateLights: CopyFrom light index {}", idx)
);
}
}

void GpuScene::UpdateMaterials(CpuScene& cpu_scene) {
const auto& frame_data = cpu_scene.GetCurrentFrameData();
auto& cmd_list = m_pending_cmd_lists.copy_queue_cmd_list;
BufferWithHandle& material_buf = m_res.material_bufs[m_current_frame_idx];

for (uint idx : frame_data.dirty_material_indices) {
cmd_list.CopyFrom(
std::span<byte>((byte*)&frame_data.materials[idx], sizeof(GMaterial)),
material_buf.buf->GetView(idx * sizeof(GMaterial), sizeof(GMaterial)),
std::format("UpdateMaterials: CopyFrom material index {}", idx)
);
}
}

void GpuScene::UpdateInstances(CpuScene& cpu_scene) {
const auto& frame_data = cpu_scene.GetCurrentFrameData();
auto& cmd_list = m_pending_cmd_lists.copy_queue_cmd_list;
BufferWithHandle& instance_buf = m_res.instance_bufs[m_current_frame_idx];

for (uint idx : frame_data.dirty_instance_indices) {
cmd_list.CopyFrom(
std::span<byte>((byte*)&frame_data.instances[idx], sizeof(GInstance)),
instance_buf.buf->GetView(idx * sizeof(GInstance), sizeof(GInstance)),
std::format("UpdateInstances: CopyFrom instance index {}", idx)
);
}
}

GpuScene::~GpuScene() noexcept {
Expand Down
Loading