From b7a88ace482b2d8647152805a929bf74c29488b7 Mon Sep 17 00:00:00 2001 From: Silverlan Date: Sun, 22 Dec 2024 21:09:21 +0100 Subject: [PATCH] feat: add global shader input component --- .../components/c_global_shader_input.hpp | 54 +++++++++++ core/client/include/pragma/game/c_game.h | 5 + .../rendering/global_shader_input_manager.hpp | 18 +++- .../shader_graph/modules/input_data.hpp | 3 - .../components/c_global_shader_input.cpp | 91 +++++++++++++++++++ core/client/src/game/c_game.cpp | 6 ++ core/client/src/game/c_game_components.cpp | 3 + core/client/src/lua/c_luaclass.cpp | 4 - core/client/src/rendering/c_render.cpp | 4 + .../shader_graph/modules/input_data.cpp | 32 ++----- 10 files changed, 188 insertions(+), 32 deletions(-) create mode 100644 core/client/include/pragma/entities/components/c_global_shader_input.hpp create mode 100644 core/client/src/entities/components/c_global_shader_input.cpp diff --git a/core/client/include/pragma/entities/components/c_global_shader_input.hpp b/core/client/include/pragma/entities/components/c_global_shader_input.hpp new file mode 100644 index 000000000..f40492b6f --- /dev/null +++ b/core/client/include/pragma/entities/components/c_global_shader_input.hpp @@ -0,0 +1,54 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2024 Silverlan + */ + +#ifndef __C_GLOBAL_SHADER_INPUT_HPP__ +#define __C_GLOBAL_SHADER_INPUT_HPP__ + +#include "pragma/clientdefinitions.h" +#include "pragma/rendering/global_shader_input_manager.hpp" +#include "pragma/entities/components/base_entity_component_member_register.hpp" +#include + +namespace pragma { + namespace rendering { + class GlobalShaderInputDataManager; + }; + class DLLCLIENT CGlobalShaderInputComponent final : public BaseEntityComponent, public DynamicMemberRegister { + public: + static void RegisterLuaBindings(lua_State *l, luabind::module_ &modEnts); + + CGlobalShaderInputComponent(BaseEntity &ent) : BaseEntityComponent(ent) {} + + virtual void Initialize() override; + virtual void InitializeLuaObject(lua_State *l) override; + virtual void OnEntitySpawn() override; + + template + bool SetShaderInputValue(const std::string_view &name, const T &val) + { + auto &inputManager = GetInputManager(); + return inputManager.SetValue(name, val); + } + + template + bool GetShaderInputValue(const std::string_view &name, T &outVal) const + { + auto &inputManager = GetInputManager(); + return inputManager.GetValue(name, outVal); + } + + virtual const ComponentMemberInfo *GetMemberInfo(ComponentMemberIndex idx) const override; + private: + virtual std::optional DoGetMemberIndex(const std::string &name) const override; + rendering::GlobalShaderInputDataManager &GetInputManager(); + const rendering::GlobalShaderInputDataManager &GetInputManager() const { return const_cast(this)->GetInputManager(); } + void UpdateComponentMembers(); + std::vector m_inputVarNames; + }; +}; + +#endif diff --git a/core/client/include/pragma/game/c_game.h b/core/client/include/pragma/game/c_game.h index 23819c9fb..61bf22c0e 100644 --- a/core/client/include/pragma/game/c_game.h +++ b/core/client/include/pragma/game/c_game.h @@ -77,6 +77,7 @@ namespace pragma { namespace rendering { class RenderQueueBuilder; class RenderQueueWorkerManager; + class GlobalShaderInputDataManager; struct GameWorldShaderSettings; struct GlobalRenderSettingsBufferData; }; @@ -397,6 +398,9 @@ class DLLCLIENT CGame : public Game { void ResetGameplayControlCamera(); pragma::CCameraComponent *GetGameplayControlCamera(); + pragma::rendering::GlobalShaderInputDataManager &GetGlobalShaderInputDataManager(); + const pragma::rendering::GlobalShaderInputDataManager &GetGlobalShaderInputDataManager() const; + pragma::rendering::RenderQueueBuilder &GetRenderQueueBuilder(); pragma::rendering::RenderQueueWorkerManager &GetRenderQueueWorkerManager(); prosper::IDescriptorSet &GetGlobalRenderSettingsDescriptorSet(); @@ -486,6 +490,7 @@ class DLLCLIENT CGame : public Game { std::vector m_sceneRenderQueue {}; std::shared_ptr m_renderQueueBuilder = nullptr; std::shared_ptr m_renderQueueWorkerManager = nullptr; + std::unique_ptr m_globalShaderInputDataManager; Vector4 m_clipPlane = {}; Vector4 m_colScale = {}; Material *m_matOverride = nullptr; diff --git a/core/client/include/pragma/rendering/global_shader_input_manager.hpp b/core/client/include/pragma/rendering/global_shader_input_manager.hpp index 184e1e3ed..f4c9b7b67 100644 --- a/core/client/include/pragma/rendering/global_shader_input_manager.hpp +++ b/core/client/include/pragma/rendering/global_shader_input_manager.hpp @@ -5,8 +5,8 @@ * Copyright (c) 2024 Silverlan */ -#ifndef __PRAGMA_GLOBAL_RENDER_SETTINGS_BUFFER_DATA_HPP__ -#define __PRAGMA_GLOBAL_RENDER_SETTINGS_BUFFER_DATA_HPP__ +#ifndef __PRAGMA_GLOBAL_SHADER_INPUT_MANAGER_HPP__ +#define __PRAGMA_GLOBAL_SHADER_INPUT_MANAGER_HPP__ #include "pragma/clientdefinitions.h" #include "pragma/rendering/shader_material/shader_material.hpp" @@ -73,6 +73,20 @@ namespace pragma::rendering { m_dirtyTracker.MarkRange(prop->offset, sizeof(T)); return true; } + + template + bool GetValue(const std::string_view &name, T &outVal) const + { + auto *prop = m_inputDescriptor->FindProperty(name.data()); + if(!prop) + return false; + auto val = m_inputData->GetValue(name.data()); + if(!val) + return false; + outVal = *val; + return true; + } + const pragma::rendering::ShaderInputData &GetData() const { return *m_inputData; } const pragma::rendering::ShaderInputDescriptor &GetDescriptor() const { return *m_inputDescriptor; } const std::shared_ptr &GetBuffer() const { return m_inputDataBuffer; } diff --git a/core/client/include/pragma/rendering/shader_graph/modules/input_data.hpp b/core/client/include/pragma/rendering/shader_graph/modules/input_data.hpp index 7bd8737a9..b93903f3e 100644 --- a/core/client/include/pragma/rendering/shader_graph/modules/input_data.hpp +++ b/core/client/include/pragma/rendering/shader_graph/modules/input_data.hpp @@ -24,8 +24,6 @@ namespace pragma::rendering { namespace pragma::rendering::shader_graph { class DLLCLIENT InputDataModule : public pragma::rendering::ShaderGraphModule { public: - static void set_shader_input_value(const std::string &name, float val); - static void set_shader_input_value(const std::string &name, const Vector3 &val); InputDataModule(prosper::Shader &shader); virtual ~InputDataModule() override; virtual void InitializeGfxPipelineDescriptorSets() override; @@ -34,7 +32,6 @@ namespace pragma::rendering::shader_graph { private: prosper::DescriptorSetInfo m_globalInputDataDsInfo; std::shared_ptr m_globalInputDsg; - static size_t g_instanceCount; }; }; diff --git a/core/client/src/entities/components/c_global_shader_input.cpp b/core/client/src/entities/components/c_global_shader_input.cpp new file mode 100644 index 000000000..209eeecd2 --- /dev/null +++ b/core/client/src/entities/components/c_global_shader_input.cpp @@ -0,0 +1,91 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2024 Silverlan + */ + +#include "stdafx_client.h" +#include "pragma/entities/components/c_global_shader_input.hpp" +#include "pragma/rendering/global_shader_input_manager.hpp" +#include "pragma/lua/lua_util_component.hpp" +#include +#include + +extern DLLCLIENT CGame *c_game; +extern DLLCLIENT CEngine *c_engine; + +using namespace pragma; +void CGlobalShaderInputComponent::RegisterLuaBindings(lua_State *l, luabind::module_ &modEnts) +{ + auto def = pragma::lua::create_entity_component_class("GlobalShaderInputComponent"); + modEnts[def]; +} + +void CGlobalShaderInputComponent::InitializeLuaObject(lua_State *l) { return BaseEntityComponent::InitializeLuaObject>(l); } + +void CGlobalShaderInputComponent::Initialize() { BaseEntityComponent::Initialize(); } + +const ComponentMemberInfo *CGlobalShaderInputComponent::GetMemberInfo(ComponentMemberIndex idx) const +{ + auto numStatic = GetStaticMemberCount(); + if(idx < numStatic) + return BaseEntityComponent::GetMemberInfo(idx); + return DynamicMemberRegister::GetMemberInfo(idx); +} + +std::optional CGlobalShaderInputComponent::DoGetMemberIndex(const std::string &name) const +{ + auto idx = BaseEntityComponent::DoGetMemberIndex(name); + if(idx.has_value()) + return idx; + idx = DynamicMemberRegister::GetMemberIndex(name); + if(idx.has_value()) + return *idx; // +GetStaticMemberCount(); + return std::optional {}; +} + +rendering::GlobalShaderInputDataManager &CGlobalShaderInputComponent::GetInputManager() { return c_game->GetGlobalShaderInputDataManager(); } + +void CGlobalShaderInputComponent::OnEntitySpawn() +{ + BaseEntityComponent::OnEntitySpawn(); + UpdateComponentMembers(); +} + +void CGlobalShaderInputComponent::UpdateComponentMembers() +{ + auto &inputManager = c_game->GetGlobalShaderInputDataManager(); + auto &descriptor = inputManager.GetDescriptor(); + ReserveMembers(descriptor.properties.size()); + m_inputVarNames.reserve(m_inputVarNames.size() + descriptor.properties.size()); + for(auto &prop : descriptor.properties) { + auto idx = BaseEntityComponent::GetMemberIndex(prop->name); + if(idx.has_value()) + continue; + auto memberInfo = pragma::ComponentMemberInfo::CreateDummy(); + memberInfo.SetName(prop->name); + memberInfo.type = static_cast(shadergraph::to_udm_type(prop.parameter.type)); + memberInfo.SetMin(prop->min); + memberInfo.SetMax(prop->max); + m_inputVarNames.push_back(prop->name); + idx = m_inputVarNames.size() - 1; + memberInfo.userIndex = *idx; + + using TComponent = CGlobalShaderInputComponent; + pragma::shadergraph::visit(prop->type, [this, &memberInfo](auto tag) { + using T = typename decltype(tag)::type; + memberInfo.SetGetterFunction([](const pragma::ComponentMemberInfo &memberInfo, TComponent &component, T &outValue) { + auto &name = component.m_inputVarNames[memberInfo.userIndex]; + component.GetShaderInputValue(name, outValue); + })>(); + memberInfo.SetSetterFunction([](const pragma::ComponentMemberInfo &memberInfo, TComponent &component, const T &value) { + auto &name = component.m_inputVarNames[memberInfo.userIndex]; + component.SetShaderInputValue(name, value); + })>(); + }); + + RegisterMember(std::move(memberInfo)); + } + OnMembersChanged(); +} diff --git a/core/client/src/game/c_game.cpp b/core/client/src/game/c_game.cpp index 20ec87c45..0dc156a59 100644 --- a/core/client/src/game/c_game.cpp +++ b/core/client/src/game/c_game.cpp @@ -58,6 +58,7 @@ #include "pragma/rendering/renderers/raytracing_renderer.hpp" #include "pragma/rendering/render_queue_worker.hpp" #include "pragma/rendering/global_render_settings_buffer_data.hpp" +#include "pragma/rendering/global_shader_input_manager.hpp" #include "pragma/ai/c_navsystem.h" #include #include @@ -257,6 +258,8 @@ CGame::CGame(NetworkState *state) m_renderQueueBuilder = std::make_unique(); m_renderQueueWorkerManager = std::make_unique(umath::clamp(cvWorkerThreadCount->GetInt(), 1, 20)); + m_globalShaderInputDataManager = std::make_unique(); + auto &texManager = static_cast(static_cast(GetNetworkState())->GetMaterialManager()).GetTextureManager(); for(auto &tex : g_requiredGameTextures) { texManager.LoadAsset(tex); // Pre-loaded in ClientState constructor @@ -327,6 +330,9 @@ void CGame::OnRemove() Game::OnRemove(); } +pragma::rendering::GlobalShaderInputDataManager &CGame::GetGlobalShaderInputDataManager() { return *m_globalShaderInputDataManager; } +const pragma::rendering::GlobalShaderInputDataManager &CGame::GetGlobalShaderInputDataManager() const { return const_cast(this)->GetGlobalShaderInputDataManager(); } + void CGame::GetRegisteredEntities(std::vector &classes, std::vector &luaClasses) const { std::unordered_map *factories = nullptr; diff --git a/core/client/src/game/c_game_components.cpp b/core/client/src/game/c_game_components.cpp index 0a68a54f7..018f1deab 100644 --- a/core/client/src/game/c_game_components.cpp +++ b/core/client/src/game/c_game_components.cpp @@ -44,6 +44,7 @@ #include "pragma/entities/components/c_optical_camera_component.hpp" #include "pragma/entities/components/c_hitbox_bvh_component.hpp" #include "pragma/entities/components/c_input_component.hpp" +#include "pragma/entities/components/c_global_shader_input.hpp" #include "pragma/entities/components/liquid/c_buoyancy_component.hpp" #include "pragma/entities/components/liquid/c_liquid_surface_component.hpp" #include "pragma/entities/components/liquid/c_liquid_volume_component.hpp" @@ -297,6 +298,8 @@ void CGame::InitializeEntityComponents(pragma::EntityComponentManager &component componentManager.RegisterComponentType("liquid_control", {"physics/fluid", hideInEditor}); componentManager.RegisterComponentType("liquid_surface_simulation", {"physics/fluid", hideInEditor}); + componentManager.RegisterComponentType("global_shader_input", {"rendering"}); + componentManager.RegisterComponentType("debug_hitbox", {"debug"}); // --template-component-register-location diff --git a/core/client/src/lua/c_luaclass.cpp b/core/client/src/lua/c_luaclass.cpp index 44ebe14cb..857bae6e4 100644 --- a/core/client/src/lua/c_luaclass.cpp +++ b/core/client/src/lua/c_luaclass.cpp @@ -133,12 +133,8 @@ static luabind::object shader_mat_value_to_lua_object(lua_State *l, const pragma }); } -#include "pragma/rendering/shader_graph/modules/input_data.hpp" static void register_shader_graph(lua_State *l, luabind::module_ &modShader) { - modShader[luabind::def("set_shader_input_value", static_cast(&pragma::rendering::shader_graph::InputDataModule::set_shader_input_value))]; - modShader[luabind::def("set_shader_input_value", static_cast(&pragma::rendering::shader_graph::InputDataModule::set_shader_input_value))]; - modShader[luabind::def( "get_test_node_register", +[]() -> std::shared_ptr { auto reg = std::make_shared(); diff --git a/core/client/src/rendering/c_render.cpp b/core/client/src/rendering/c_render.cpp index 8bb2d67cc..90c3a5373 100644 --- a/core/client/src/rendering/c_render.cpp +++ b/core/client/src/rendering/c_render.cpp @@ -18,6 +18,7 @@ #include "pragma/entities/components/c_player_component.hpp" #include #include "pragma/rendering/renderers/rasterization_renderer.hpp" +#include "pragma/rendering/global_shader_input_manager.hpp" #include "pragma/console/c_cvar.h" #include "pragma/console/c_cvar_global_functions.h" #include "pragma/entities/components/c_vehicle_component.hpp" @@ -350,6 +351,9 @@ void CGame::RenderScenes(util::DrawSceneInfo &drawSceneInfo) GetGlobalRenderSettingsBufferData().EvaluateDebugPrint(); #endif + auto &inputDataManager = GetGlobalShaderInputDataManager(); + inputDataManager.UpdateBufferData(*drawSceneInfo.commandBuffer); + StartProfilingStage("RenderScenes"); util::ScopeGuard sg {[this]() { StopProfilingStage(); // RenderScenes diff --git a/core/client/src/rendering/shader_graph/modules/input_data.cpp b/core/client/src/rendering/shader_graph/modules/input_data.cpp index b4fda63ef..8045b3e47 100644 --- a/core/client/src/rendering/shader_graph/modules/input_data.cpp +++ b/core/client/src/rendering/shader_graph/modules/input_data.cpp @@ -18,40 +18,25 @@ using namespace pragma::rendering::shader_graph; extern DLLCLIENT CEngine *c_engine; +extern DLLCLIENT CGame *c_game; -static std::unique_ptr g_globalShaderInputDataManager {}; -size_t InputDataModule::g_instanceCount = 0; InputDataModule::InputDataModule(prosper::Shader &shader) : pragma::rendering::ShaderGraphModule {shader} { - if(g_instanceCount == 0) - g_globalShaderInputDataManager = std::make_unique(); m_globalInputDataDsInfo = { "SHADER_GRAPH", {prosper::DescriptorSetInfo::Binding {"GLOBAL_INPUT_DATA", prosper::DescriptorType::UniformBuffer, prosper::ShaderStageFlags::FragmentBit | prosper::ShaderStageFlags::VertexBit | prosper::ShaderStageFlags::GeometryBit}}, }; } -InputDataModule::~InputDataModule() -{ - if(--g_instanceCount == 0) { - g_globalShaderInputDataManager = nullptr; - } -} - -void pragma::rendering::shader_graph::InputDataModule::set_shader_input_value(const std::string &name, float val) -{ - g_globalShaderInputDataManager->SetValue(name, val); - - auto cmd = c_engine->GetRenderContext().GetSetupCommandBuffer(); - g_globalShaderInputDataManager->UpdateBufferData(*cmd); - c_engine->GetRenderContext().FlushSetupCommandBuffer(); -} +InputDataModule::~InputDataModule() {} void InputDataModule::GetShaderPreprocessorDefinitions(std::unordered_map &outDefinitions, std::string &outPrefixCode) { + auto &inputDataManager = c_game->GetGlobalShaderInputDataManager(); + std::ostringstream code; code << "\nlayout(LAYOUT_ID(SHADER_GRAPH, GLOBAL_INPUT_DATA)) uniform GlobalInputData\n"; code << "{\n"; - for(auto &prop : g_globalShaderInputDataManager->GetDescriptor().properties) { + for(auto &prop : inputDataManager.GetDescriptor().properties) { if(prop.parameter.name.empty()) continue; code << "\t" << pragma::shadergraph::to_glsl_type(prop.parameter.type) << " " << prop.parameter.name << ";\n"; @@ -62,11 +47,12 @@ void InputDataModule::GetShaderPreprocessorDefinitions(std::unordered_mapGetGlobalShaderInputDataManager(); // TODO: auto testPbr = c_engine->GetShaderGraphManager().GetGraph("z"); - g_globalShaderInputDataManager->PopulateProperties(*testPbr->GetGraph()); + inputDataManager.PopulateProperties(*testPbr->GetGraph()); auto cmd = c_engine->GetRenderContext().GetSetupCommandBuffer(); - g_globalShaderInputDataManager->UpdateBufferData(*cmd); + inputDataManager.UpdateBufferData(*cmd); c_engine->GetRenderContext().FlushSetupCommandBuffer(); m_shader.AddDescriptorSetGroup(m_globalInputDataDsInfo); @@ -79,7 +65,7 @@ void InputDataModule::InitializeGfxPipelineDescriptorSets() auto &dummyCubemapTex = context.GetDummyCubemapTexture(); auto &ds = *m_globalInputDsg->GetDescriptorSet(0); constexpr uint32_t BINDING_IDX = 0; - auto buf = g_globalShaderInputDataManager->GetBuffer(); + auto buf = inputDataManager.GetBuffer(); if(!buf) buf = c_engine->GetRenderContext().GetDummyBuffer(); ds.SetBindingUniformBuffer(*buf, BINDING_IDX);