Skip to content

Commit

Permalink
feat: improve performance of world render queue building
Browse files Browse the repository at this point in the history
  • Loading branch information
Silverlan committed Dec 25, 2024
1 parent 6ece427 commit 510a958
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,14 @@ namespace pragma {
virtual void OnTick(double tDelta) override;
void FlushRenderData();

void UpdateRenderBufferList();
void UpdateRenderMeshes(bool requireBoundingVolumeUpdate = true);
void ReloadRenderBufferList(bool immediate = false);
// Only use if LOD is handled externally!
void SetLOD(uint32_t lod);
protected:
void UpdateBaseShaderSpecializationFlags();
virtual void OnModelChanged(const std::shared_ptr<Model> &model) override;
void UpdateRenderBufferList();

std::unordered_map<const CModelSubMesh *, std::shared_ptr<prosper::IBuffer>> m_lightmapUvBuffers {};
std::vector<msys::MaterialHandle> m_materialOverrides = {};
Expand Down
89 changes: 50 additions & 39 deletions core/client/src/entities/c_world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "pragma/rendering/render_processor.hpp"
#include "pragma/lua/c_lentity_handles.hpp"
#include <buffers/prosper_buffer.hpp>
#include <sharedutils/BS_thread_pool.hpp>
#include <prosper_util.hpp>
#include <pragma/entities/entity_iterator.hpp>
#include <pragma/entities/components/base_transform_component.hpp>
Expand Down Expand Up @@ -273,49 +274,59 @@ void CWorldComponent::BuildOfflineRenderQueues(bool rebuild)
}
}

clusterRenderQueues.reserve(numClusters);
clusterRenderTranslucentQueues.reserve(numClusters);
clusterRenderQueues.resize(numClusters);
clusterRenderTranslucentQueues.resize(numClusters);
BS::thread_pool tp {std::thread::hardware_concurrency()};
std::atomic<bool> failure {false};
auto &context = c_engine->GetRenderContext();
for(auto clusterIdx = decltype(meshesPerClusters.size()) {0u}; clusterIdx < meshesPerClusters.size(); ++clusterIdx) {
clusterRenderQueues.push_back(pragma::rendering::RenderQueue::Create("world_cluster_" + std::to_string(clusterIdx)));
std::shared_ptr<pragma::rendering::RenderQueue> clusterRenderTranslucentQueue = nullptr;
auto &clusterRenderQueue = clusterRenderQueues.back();
auto &meshes = meshesPerClusters.at(clusterIdx);
for(auto subMeshIdx : meshes) {
if(subMeshIdx >= renderMeshes.size()) {
// Something went wrong (Maybe world model is missing?)
clusterRenderQueues.clear();
clusterRenderTranslucentQueues.clear();
tp.submit_blocks<size_t>(0u, meshesPerClusters.size(), [&](size_t start, size_t end) {
for(auto clusterIdx = start; clusterIdx < end; ++clusterIdx) {
if(failure == true)
return;
auto clusterRenderQueue = pragma::rendering::RenderQueue::Create("world_cluster_" + std::to_string(clusterIdx));
clusterRenderQueues[clusterIdx] = clusterRenderQueue;
std::shared_ptr<pragma::rendering::RenderQueue> clusterRenderTranslucentQueue = nullptr;
auto &meshes = meshesPerClusters.at(clusterIdx);
for(auto subMeshIdx : meshes) {
if(subMeshIdx >= renderMeshes.size()) {
failure = true;
return;
}
auto subMesh = renderMeshes.at(subMeshIdx);
auto *mat = mdlC->GetRenderMaterial(subMesh->GetSkinTextureIndex());
if(mat == nullptr)
continue;
auto hShader = mat->GetPrimaryShader();
if(!hShader)
continue;
auto *shader = dynamic_cast<pragma::ShaderGameWorldLightingPass *>(hShader);
if(shader == nullptr)
continue;
uint32_t pipelineIdx = 0;
auto t = shader->FindPipelineIndex(pragma::rendering::PassType::Generic, renderC->GetShaderPipelineSpecialization(), shader->GetMaterialPipelineSpecializationRequirements(*mat)); // | pragma::GameShaderSpecializationConstantFlag::Enable3dOriginBit);
if(t.has_value())
pipelineIdx = *t;
prosper::PipelineID pipelineId;
if(shader->GetPipelineId(pipelineId, pipelineIdx) == false || pipelineId == std::numeric_limits<decltype(pipelineId)>::max())
continue;
if(mat->GetAlphaMode() == AlphaMode::Blend || shader->IsTranslucentPipeline(pipelineIdx)) {
clusterRenderTranslucentQueue = clusterRenderTranslucentQueue ? clusterRenderTranslucentQueue : pragma::rendering::RenderQueue::Create("world_translucent_cluster_" + std::to_string(clusterIdx));
clusterRenderTranslucentQueue->Add(static_cast<CBaseEntity &>(GetEntity()), subMeshIdx, *mat, pipelineId);
continue;
}
clusterRenderQueue->Add(static_cast<CBaseEntity &>(GetEntity()), subMeshIdx, *mat, pipelineId);
}
auto subMesh = renderMeshes.at(subMeshIdx);
auto *mat = mdlC->GetRenderMaterial(subMesh->GetSkinTextureIndex());
if(mat == nullptr)
continue;
auto hShader = mat->GetPrimaryShader();
if(!hShader)
continue;
auto *shader = dynamic_cast<pragma::ShaderGameWorldLightingPass *>(hShader);
if(shader == nullptr)
continue;
uint32_t pipelineIdx = 0;
auto t = shader->FindPipelineIndex(pragma::rendering::PassType::Generic, renderC->GetShaderPipelineSpecialization(), shader->GetMaterialPipelineSpecializationRequirements(*mat)); // | pragma::GameShaderSpecializationConstantFlag::Enable3dOriginBit);
if(t.has_value())
pipelineIdx = *t;
prosper::PipelineID pipelineId;
if(shader->GetPipelineId(pipelineId, pipelineIdx) == false || pipelineId == std::numeric_limits<decltype(pipelineId)>::max())
continue;
if(mat->GetAlphaMode() == AlphaMode::Blend) {
clusterRenderTranslucentQueue = clusterRenderTranslucentQueue ? clusterRenderTranslucentQueue : pragma::rendering::RenderQueue::Create("world_translucent_cluster_" + std::to_string(clusterIdx));
clusterRenderTranslucentQueue->Add(static_cast<CBaseEntity &>(GetEntity()), subMeshIdx, *mat, pipelineId);
continue;
}
clusterRenderQueue->Add(static_cast<CBaseEntity &>(GetEntity()), subMeshIdx, *mat, pipelineId);
clusterRenderTranslucentQueues[clusterIdx] = clusterRenderTranslucentQueue;
clusterRenderQueue->Sort();
if(clusterRenderTranslucentQueue)
clusterRenderTranslucentQueue->Sort();
}
clusterRenderTranslucentQueues.push_back(clusterRenderTranslucentQueue);
clusterRenderQueue->Sort();
if(clusterRenderTranslucentQueue)
clusterRenderTranslucentQueue->Sort();
});
tp.wait();
if(failure == true) {
// Something went wrong (Maybe world model is missing?)
clusterRenderQueues.clear();
clusterRenderTranslucentQueues.clear();
}
}

Expand Down
6 changes: 3 additions & 3 deletions core/client/src/entities/components/c_model_component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,22 @@ void CModelComponent::SetMaterialOverride(uint32_t idx, CMaterial &mat)
if(idx >= m_materialOverrides.size())
m_materialOverrides.resize(idx + 1);
m_materialOverrides.at(idx) = mat.GetHandle();
umath::set_flag(m_stateFlags, StateFlags::RenderMeshUpdateRequired);
umath::set_flag(m_stateFlags, StateFlags::RenderBufferListUpdateRequired);
mat.UpdateTextures(); // Ensure all textures have been fully loaded
}
void CModelComponent::ClearMaterialOverride(uint32_t idx)
{
if(idx >= m_materialOverrides.size())
return;
m_materialOverrides.at(idx) = {};
umath::set_flag(m_stateFlags, StateFlags::RenderMeshUpdateRequired);
umath::set_flag(m_stateFlags, StateFlags::RenderBufferListUpdateRequired);
}
void CModelComponent::ClearMaterialOverrides()
{
if(m_materialOverrides.empty())
return;
m_materialOverrides.clear();
umath::set_flag(m_stateFlags, StateFlags::RenderMeshUpdateRequired);
umath::set_flag(m_stateFlags, StateFlags::RenderBufferListUpdateRequired);
BroadcastEvent(EVENT_ON_MATERIAL_OVERRIDES_CLEARED);
}
CMaterial *CModelComponent::GetMaterialOverride(uint32_t idx) const { return (idx < m_materialOverrides.size()) ? static_cast<CMaterial *>(m_materialOverrides.at(idx).get()) : nullptr; }
Expand Down
13 changes: 5 additions & 8 deletions core/client/src/lua/classes/component/c_lmodel_component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ void Lua::ModelDef::register_class(lua_State *l, luabind::module_ &entsMod)
defCModel.def("ClearMaterialOverride", &pragma::CModelComponent::ClearMaterialOverride);
defCModel.def("ClearMaterialOverrides", &pragma::CModelComponent::ClearMaterialOverrides);
defCModel.def("GetMaterialOverride", &pragma::CModelComponent::GetMaterialOverride);
defCModel.def(
"GetMaterialOverrideCount", +[](pragma::CModelComponent &c) -> size_t { return c.GetMaterialOverrides().size(); });
defCModel.def("GetMaterialOverrideCount", +[](pragma::CModelComponent &c) -> size_t { return c.GetMaterialOverrides().size(); });
defCModel.def("GetRenderMaterial", static_cast<CMaterial *(pragma::CModelComponent::*)(uint32_t, uint32_t) const>(&pragma::CModelComponent::GetRenderMaterial));
defCModel.def("GetRenderMaterial", static_cast<CMaterial *(pragma::CModelComponent::*)(uint32_t) const>(&pragma::CModelComponent::GetRenderMaterial));
defCModel.def("GetLOD", &pragma::CModelComponent::GetLOD);
Expand All @@ -91,23 +90,21 @@ void Lua::ModelDef::register_class(lua_State *l, luabind::module_ &entsMod)
defCModel.def("GetMaxDrawDistance", &pragma::CModelComponent::GetMaxDrawDistance);
defCModel.def("UpdateRenderMeshes", &pragma::CModelComponent::UpdateRenderMeshes, luabind::default_parameter_policy<2, true> {});
defCModel.def("UpdateRenderMeshes", &pragma::CModelComponent::UpdateRenderMeshes);
defCModel.def("UpdateRenderBufferList", &pragma::CModelComponent::UpdateRenderBufferList);
defCModel.def("SetRenderMeshesDirty", &pragma::CModelComponent::SetRenderMeshesDirty);
defCModel.def("ReloadRenderBufferList", &pragma::CModelComponent::ReloadRenderBufferList, luabind::default_parameter_policy<2, false> {});
defCModel.def("ReloadRenderBufferList", &pragma::CModelComponent::ReloadRenderBufferList);
defCModel.def("IsDepthPrepassEnabled", &pragma::CModelComponent::IsDepthPrepassEnabled);
defCModel.def("SetDepthPrepassEnabled", &pragma::CModelComponent::SetDepthPrepassEnabled);
defCModel.def("SetRenderBufferData", &pragma::CModelComponent::SetRenderBufferData);
defCModel.def(
"GetRenderBufferData", +[](pragma::CModelComponent &c) -> std::vector<pragma::rendering::RenderBufferData> { return c.GetRenderBufferData(); });
defCModel.def("GetRenderBufferData", +[](pragma::CModelComponent &c) -> std::vector<pragma::rendering::RenderBufferData> { return c.GetRenderBufferData(); });
defCModel.def("AddRenderMesh", &pragma::CModelComponent::AddRenderMesh);
defCModel.def("AddRenderMesh", &pragma::CModelComponent::AddRenderMesh, luabind::default_parameter_policy<4, pragma::rendering::RenderBufferData::StateFlags::EnableDepthPrepass> {});
defCModel.def(
"GetRenderMeshes", +[](pragma::CModelComponent &c) -> std::vector<std::shared_ptr<ModelSubMesh>> { return c.GetRenderMeshes(); });
defCModel.def("GetRenderMeshes", +[](pragma::CModelComponent &c) -> std::vector<std::shared_ptr<ModelSubMesh>> { return c.GetRenderMeshes(); });
defCModel.def("GetBaseShaderSpecializationFlags", &pragma::CModelComponent::GetBaseShaderSpecializationFlags);
defCModel.def("SetBaseShaderSpecializationFlags", &pragma::CModelComponent::SetBaseShaderSpecializationFlags);
defCModel.def("SetBaseShaderSpecializationFlag", &pragma::CModelComponent::SetBaseShaderSpecializationFlag);
defCModel.def(
"SetBaseShaderSpecializationFlag", +[](pragma::CModelComponent &c, pragma::GameShaderSpecializationConstantFlag flag) { c.SetBaseShaderSpecializationFlag(flag); });
defCModel.def("SetBaseShaderSpecializationFlag", +[](pragma::CModelComponent &c, pragma::GameShaderSpecializationConstantFlag flag) { c.SetBaseShaderSpecializationFlag(flag); });
defCModel.def("GetStaticShaderSpecializationFlags", &pragma::CModelComponent::GetStaticShaderSpecializationFlags);
defCModel.def("SetStaticShaderSpecializationFlags", &pragma::CModelComponent::SetStaticShaderSpecializationFlags);

Expand Down

0 comments on commit 510a958

Please sign in to comment.