diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2016dd7f..97fd9b38 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,7 +35,7 @@ jobs: if: runner.os == 'macOS' - name: Checkout Repo - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup cmake uses: jwlawson/actions-setup-cmake@v2 @@ -43,7 +43,7 @@ jobs: cmake-version: ${{env.CMAKE_VERSION}} - name: Update Cache Files - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{github.workspace}}/ThirdParty/Zip key: ${{runner.os}}-3rd-zip diff --git a/Engine/Source/Common/Include/Common/File.h b/Engine/Source/Common/Include/Common/File.h index 6b641284..65f808d2 100644 --- a/Engine/Source/Common/Include/Common/File.h +++ b/Engine/Source/Common/Include/Common/File.h @@ -6,9 +6,13 @@ #include +#include + namespace Common { class FileUtils { public: - static std::string ReadTextFile(const std::string& fileName); + static std::string ReadTextFile(const std::string& inFileName); + static rapidjson::Document ReadJsonFile(const std::string& inFileName); + static void WriteJsonFile(const std::string& inFileName, const rapidjson::Document& inJsonDocument, bool inPretty = true); }; } diff --git a/Engine/Source/Common/Include/Common/FileSystem.h b/Engine/Source/Common/Include/Common/FileSystem.h index 1954ba4d..fbd9f027 100644 --- a/Engine/Source/Common/Include/Common/FileSystem.h +++ b/Engine/Source/Common/Include/Common/FileSystem.h @@ -5,6 +5,7 @@ #pragma once #include +#include namespace Common { class Path { diff --git a/Engine/Source/Common/Include/Common/Serialization.h b/Engine/Source/Common/Include/Common/Serialization.h index 23332af9..dcaa5185 100644 --- a/Engine/Source/Common/Include/Common/Serialization.h +++ b/Engine/Source/Common/Include/Common/Serialization.h @@ -15,18 +15,16 @@ #include #include #include +#include #include -#include -#include -#include -#include #include #include #include #include #include +#include namespace Common { class BinarySerializeStream { @@ -476,39 +474,15 @@ namespace Common { template void JsonSerializeToFile(const std::string& inFile, const T& inValue, bool inPretty) { - Common::Path parentPath = Common::Path(inFile).Parent(); - if (!parentPath.Exists()) { - parentPath.MakeDir(); - } - rapidjson::Document document; JsonSerialize(document, document.GetAllocator(), inValue); - - char buffer[65536]; - std::FILE* file = fopen(inFile.c_str(), "wb"); - rapidjson::FileWriteStream stream(file, buffer, sizeof(buffer)); - - if (inPretty) { - rapidjson::PrettyWriter writer(stream); - document.Accept(writer); - } else { - rapidjson::Writer writer(stream); - document.Accept(writer); - } - (void) fclose(file); + FileUtils::WriteJsonFile(inFile, document, inPretty); } template void JsonDeserializeFromFile(const std::string& inFile, T& outValue) { - char buffer[65536]; - std::FILE* file = fopen(inFile.c_str(), "rb"); - rapidjson::FileReadStream stream(file, buffer, sizeof(buffer)); - - rapidjson::Document document; - document.ParseStream(stream); - + const rapidjson::Document document = FileUtils::ReadJsonFile(inFile); JsonDeserialize(document, outValue); - (void) fclose(file); } template @@ -982,21 +956,21 @@ namespace Common { template static size_t SerializeInternal(BinarySerializeStream& stream, const std::tuple& value, std::index_sequence) { - size_t result = 0; + size_t serialized = 0; std::initializer_list { ([&]() -> void { - result += Serializer::Serialize(stream, std::get(value)); + serialized += Serializer::Serialize(stream, std::get(value)); }(), 0)... }; - return result; + return serialized; } template static size_t DeserializeInternal(BinaryDeserializeStream& stream, std::tuple& value, std::index_sequence) { - size_t result = 0; + size_t deserialized = 0; std::initializer_list { ([&]() -> void { - result += Serializer::Deserialize(stream, std::get(value)); + deserialized += Serializer::Deserialize(stream, std::get(value)); }(), 0)... }; - return result; + return deserialized; } static size_t Serialize(BinarySerializeStream& stream, const std::tuple& value) @@ -1035,6 +1009,51 @@ namespace Common { } }; + template struct VariantTypeId {}; + template struct VariantTypeId { static constexpr size_t value = HashUtils::StrCrc32("std::variant"); }; + template struct VariantTypeId { static constexpr size_t value = Serializer::typeId + VariantTypeId::value; }; + + template + struct Serializer> { + static constexpr size_t typeId = VariantTypeId::value; + + static size_t Serialize(BinarySerializeStream& stream, const std::variant& value) + { + size_t serialized = 0; + serialized += Serializer::Serialize(stream, value.index()); + std::visit([&](auto&& v) -> void { // NOLINT + serialized += Serializer>::Serialize(stream, v); + }, value); + return serialized; + } + + template + static size_t DeserializeInternal(BinaryDeserializeStream& stream, std::variant& value, size_t aspectIndex, std::index_sequence) + { + size_t deserialized = 0; + (void) std::initializer_list { ([&]() -> void { + if (I != aspectIndex) { + return; + } + + T tempValue; + deserialized += Serializer::Deserialize(stream, tempValue); + value = std::move(tempValue); + }(), 0)... }; + return deserialized; + } + + static size_t Deserialize(BinaryDeserializeStream& stream, std::variant& value) + { + size_t deserialized = 0; + + uint64_t index; + deserialized += Serializer::Deserialize(stream, index); + deserialized += DeserializeInternal(stream, value, index, std::make_index_sequence {}); + return deserialized; + } + }; + template <> struct JsonSerializer { static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const int8_t& inValue) @@ -1528,4 +1547,47 @@ namespace Common { JsonDeserializeInternal(inJsonValue, outValue, std::make_index_sequence()); } }; + + template + struct JsonSerializer> { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const std::variant& inValue) + { + rapidjson::Value typeValue; + JsonSerializer::JsonSerialize(typeValue, inAllocator, inValue.index()); + + rapidjson::Value contentValue; + std::visit([&](auto&& v) -> void { + JsonSerializer>::JsonSerialize(contentValue, inAllocator, v); + }, inValue); + + outJsonValue.SetObject(); + outJsonValue.AddMember("type", typeValue, inAllocator); + outJsonValue.AddMember("content", contentValue, inAllocator); + } + + template + static void JsonDeserializeInternal(const rapidjson::Value& inContentJsonValue, std::variant& outValue, size_t inAspectIndex, std::index_sequence) + { + (void) std::initializer_list { ([&]() -> void { + if (I != inAspectIndex) { + return; + } + + T temp; + JsonSerializer::JsonDeserialize(inContentJsonValue, temp); + outValue = std::move(temp); + }(), 0)... }; + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, std::variant& outValue) + { + if (!inJsonValue.HasMember("type") || !inJsonValue.HasMember("content")) { + return; + } + + uint64_t aspectIndex; + JsonSerializer::JsonDeserialize(inJsonValue["type"], aspectIndex); + JsonDeserializeInternal(inJsonValue["content"], outValue, aspectIndex, std::make_index_sequence {}); + } + }; } diff --git a/Engine/Source/Common/Include/Common/Time.h b/Engine/Source/Common/Include/Common/Time.h index efdd222e..dd38e352 100644 --- a/Engine/Source/Common/Include/Common/Time.h +++ b/Engine/Source/Common/Include/Common/Time.h @@ -18,8 +18,8 @@ namespace Common { Time ToTime() const; AccurateTime ToAccurateTime() const; - float ToSeconds() const; - float ToMilliseconds() const; + double ToSeconds() const; + double ToMilliseconds() const; uint64_t ToMicroseconds() const; const std::chrono::system_clock::time_point& GetNative() const; diff --git a/Engine/Source/Common/Src/File.cpp b/Engine/Source/Common/Src/File.cpp index 69cbbbe1..9300dece 100644 --- a/Engine/Source/Common/Src/File.cpp +++ b/Engine/Source/Common/Src/File.cpp @@ -3,16 +3,23 @@ // #include +#include + +#include +#include +#include +#include #include #include +#include namespace Common { - std::string FileUtils::ReadTextFile(const std::string& fileName) + std::string FileUtils::ReadTextFile(const std::string& inFileName) { std::string result; { - std::ifstream file(fileName, std::ios::ate | std::ios::binary); + std::ifstream file(inFileName, std::ios::ate | std::ios::binary); Assert(file.is_open()); const size_t size = file.tellg(); result.resize(size); @@ -22,4 +29,37 @@ namespace Common { } return result; } + + rapidjson::Document FileUtils::ReadJsonFile(const std::string& inFileName) + { + char buffer[65536]; + std::FILE* file = fopen(inFileName.c_str(), "rb"); // NOLINT + rapidjson::FileReadStream stream(file, buffer, sizeof(buffer)); + + rapidjson::Document document; + document.ParseStream(stream); + (void) fclose(file); + return document; + } + + void FileUtils::WriteJsonFile(const std::string& inFileName, const rapidjson::Document& inJsonDocument, bool inPretty) + { + Common::Path parentPath = Common::Path(inFileName).Parent(); + if (!parentPath.Exists()) { + parentPath.MakeDir(); + } + + char buffer[65536]; + std::FILE* file = fopen(inFileName.c_str(), "wb"); // NOLINT + rapidjson::FileWriteStream stream(file, buffer, sizeof(buffer)); + + if (inPretty) { + rapidjson::PrettyWriter writer(stream); + inJsonDocument.Accept(writer); + } else { + rapidjson::Writer writer(stream); + inJsonDocument.Accept(writer); + } + (void) fclose(file); + } } diff --git a/Engine/Source/Common/Src/Time.cpp b/Engine/Source/Common/Src/Time.cpp index 398ad2f3..4a935a5d 100644 --- a/Engine/Source/Common/Src/Time.cpp +++ b/Engine/Source/Common/Src/Time.cpp @@ -45,14 +45,14 @@ namespace Common { return AccurateTime { *this }; } - float TimePoint::ToSeconds() const + double TimePoint::ToSeconds() const { - return ToMilliseconds() / 1000.0f; + return ToMilliseconds() / 1000.0; } - float TimePoint::ToMilliseconds() const + double TimePoint::ToMilliseconds() const { - return static_cast(ToMicroseconds()) / 1000.0f; + return static_cast(ToMicroseconds()) / 1000.0; } uint64_t TimePoint::ToMicroseconds() const diff --git a/Engine/Source/Common/Test/SerializationTest.cpp b/Engine/Source/Common/Test/SerializationTest.cpp index f4e7a942..3837cc41 100644 --- a/Engine/Source/Common/Test/SerializationTest.cpp +++ b/Engine/Source/Common/Test/SerializationTest.cpp @@ -2,8 +2,6 @@ // Created by johnk on 2023/7/13. // -#include - #include #include @@ -76,6 +74,7 @@ TEST(SerializationTest, TypedSerializationTest) PerformTypedSerializationTest>({ { 1, false }, { 2, true } }); PerformTypedSerializationTest>({ { 1, false }, { 2, true } }); PerformTypedSerializationTest>({ 1, true, 2 }); + PerformTypedSerializationTest>({ true }); } TEST(SerializationTest, TypedSerializationWithFileTest) @@ -107,6 +106,7 @@ TEST(SerializationTest, TypedSerializationWithFileTest) PerformTypeSerializationWithFileTest>(fileName, { { 1, false }, { 2, true } }); PerformTypeSerializationWithFileTest>(fileName, { { 1, false }, { 2, true } }); PerformTypeSerializationWithFileTest>(fileName, { 1, true, 2 }); + PerformTypeSerializationWithFileTest>(fileName, { true }); } TEST(SerializationTest, JsonSerializationTest) @@ -137,6 +137,7 @@ TEST(SerializationTest, JsonSerializationTest) PerformJsonSerializationTest>({ { 1, false }, { 2, true } }, R"([{"key":1,"value":false},{"key":2,"value":true}])"); PerformJsonSerializationTest>({ { "1", 1 }, { "2", 2 } }, R"([{"key":"1","value":1},{"key":"2","value":2}])"); PerformJsonSerializationTest>({ 1, true, 2 }, R"({"0":1,"1":true,"2":2})"); + PerformJsonSerializationTest>({ true }, R"({"type":1,"content":true})"); } TEST(SerializationTest, JsonSerializationWithFileTest) @@ -169,4 +170,5 @@ TEST(SerializationTest, JsonSerializationWithFileTest) PerformJsonSerializationWithFileTest>(fileName, { { 1, false }, { 2, true } }); PerformJsonSerializationWithFileTest>(fileName, { { "1", 1 }, { "2", 2 } }); PerformJsonSerializationWithFileTest>(fileName, { 1, true, 2 }); + PerformTypeSerializationWithFileTest>(fileName, { true }); } diff --git a/Engine/Source/Core/Include/Core/Console.h b/Engine/Source/Core/Include/Core/Console.h index 1a6fe1f7..3d16bc51 100644 --- a/Engine/Source/Core/Include/Core/Console.h +++ b/Engine/Source/Core/Include/Core/Console.h @@ -4,6 +4,8 @@ #pragma once +#include + #include #include #include @@ -14,8 +16,7 @@ namespace Core { enum class CSFlagBits : uint8_t { configOverridable = 0x1, - settingsOverridable = 0x2, - max = 0x4 + max = 0x2 }; using CSFlags = Common::Flags; DECLARE_FLAG_BITS_OP(CSFlags, CSFlagBits) @@ -63,7 +64,7 @@ namespace Core { virtual void SetString(const std::string& inValue) = 0; protected: - ConsoleSetting(const std::string& inName, const std::string& inDescription, const CSFlags& inFlags = CSFlags::null); + ConsoleSetting(const std::string& inName, const std::string& inDescription, const CSFlags& inFlags); virtual void PerformRenderThreadCopy() = 0; @@ -141,6 +142,7 @@ namespace Core { ConsoleSetting& GetSetting(const std::string& inName) const; template ConsoleSettingValue* FindSettingValue(const std::string& inName) const; template ConsoleSettingValue& GetSettingValue(const std::string& inName) const; + void OverrideSettingsByConfig() const; void PerformRenderThreadSettingsCopy() const; private: @@ -218,8 +220,10 @@ namespace Core { return Common::ToArithmetic(Get()); } else if constexpr (Common::CppBool) { return Get() ? 1 : 0; - } else { + } else if constexpr (Common::CppArithmetic) { return static_cast(Get()); + } else { + Unimplement(); } } @@ -230,8 +234,10 @@ namespace Core { return Common::ToArithmetic(Get()); } else if constexpr (Common::CppBool) { return Get() ? 1 : 0; - } else { + } else if constexpr (Common::CppArithmetic) { return static_cast(Get()); + } else { + Unimplement(); } } @@ -242,8 +248,10 @@ namespace Core { return Common::ToArithmetic(Get()); } else if constexpr (Common::CppBool) { return Get() ? 1 : 0; - } else { + } else if constexpr (Common::CppArithmetic) { return static_cast(Get()); + } else { + Unimplement(); } } @@ -254,8 +262,10 @@ namespace Core { return Common::ToArithmetic(Get()); } else if constexpr (Common::CppBool) { return Get() ? 1 : 0; - } else { + } else if constexpr (Common::CppArithmetic) { return static_cast(Get()); + } else { + Unimplement(); } } @@ -266,8 +276,10 @@ namespace Core { return Common::ToArithmetic(Get()); } else if constexpr (Common::CppBool) { return Get() ? 1 : 0; - } else { + } else if constexpr (Common::CppArithmetic) { return static_cast(Get()); + } else { + Unimplement(); } } @@ -278,8 +290,10 @@ namespace Core { return Common::ToArithmetic(Get()); } else if constexpr (Common::CppBool) { return Get() ? 1 : 0; - } else { + } else if constexpr (Common::CppArithmetic) { return static_cast(Get()); + } else { + Unimplement(); } } @@ -290,8 +304,10 @@ namespace Core { return Common::ToArithmetic(Get()); } else if constexpr (Common::CppBool) { return Get() ? 1 : 0; - } else { + } else if constexpr (Common::CppArithmetic) { return static_cast(Get()); + } else { + Unimplement(); } } @@ -302,8 +318,10 @@ namespace Core { return Common::ToArithmetic(Get()); } else if constexpr (Common::CppBool) { return Get() ? 1 : 0; - } else { + } else if constexpr (Common::CppArithmetic) { return static_cast(Get()); + } else { + Unimplement(); } } @@ -314,8 +332,10 @@ namespace Core { return Common::ToArithmetic(Get()); } else if constexpr (Common::CppBool) { return Get(); - } else { + } else if constexpr (Common::CppArithmetic) { return Get() != 0; + } else { + Unimplement(); } } @@ -326,8 +346,10 @@ namespace Core { return Common::ToArithmetic(Get()); } else if constexpr (Common::CppBool) { return Get() ? 1.0f : 0.0f; - } else { + } else if constexpr (Common::CppArithmetic) { return static_cast(Get()); + } else { + Unimplement(); } } @@ -338,8 +360,10 @@ namespace Core { return Common::ToArithmetic(Get()); } else if constexpr (Common::CppBool) { return Get() ? 1.0 : 0.0; - } else { + } else if constexpr (Common::CppArithmetic) { return static_cast(Get()); + } else { + Unimplement(); } } @@ -350,8 +374,10 @@ namespace Core { return Get(); } else if constexpr (Common::CppBool) { return Get() ? "true" : "false"; - } else { + } else if constexpr (Common::CppArithmetic) { return Common::ToString(Get()); + } else { + Unimplement(); } } @@ -362,8 +388,10 @@ namespace Core { Set(Common::ToString(inValue)); } else if constexpr (Common::CppBool) { Set(inValue != 0); - } else { + } else if constexpr (Common::CppArithmetic) { Set(static_cast(inValue)); + } else { + Unimplement(); } } @@ -374,8 +402,10 @@ namespace Core { Set(Common::ToString(inValue)); } else if constexpr (Common::CppBool) { Set(inValue != 0); - } else { + } else if constexpr (Common::CppArithmetic) { Set(static_cast(inValue)); + } else { + Unimplement(); } } @@ -386,8 +416,10 @@ namespace Core { Set(Common::ToString(inValue)); } else if constexpr (Common::CppBool) { Set(inValue != 0); - } else { + } else if constexpr (Common::CppArithmetic) { Set(static_cast(inValue)); + } else { + Unimplement(); } } @@ -398,8 +430,10 @@ namespace Core { Set(Common::ToString(inValue)); } else if constexpr (Common::CppBool) { Set(inValue != 0); - } else { + } else if constexpr (Common::CppArithmetic) { Set(static_cast(inValue)); + } else { + Unimplement(); } } @@ -410,8 +444,10 @@ namespace Core { Set(Common::ToString(inValue)); } else if constexpr (Common::CppBool) { Set(inValue != 0); - } else { + } else if constexpr (Common::CppArithmetic) { Set(static_cast(inValue)); + } else { + Unimplement(); } } @@ -422,8 +458,10 @@ namespace Core { Set(Common::ToString(inValue)); } else if constexpr (Common::CppBool) { Set(inValue != 0); - } else { + } else if constexpr (Common::CppArithmetic) { Set(static_cast(inValue)); + } else { + Unimplement(); } } @@ -434,8 +472,10 @@ namespace Core { Set(Common::ToString(inValue)); } else if constexpr (Common::CppBool) { Set(inValue != 0); - } else { + } else if constexpr (Common::CppArithmetic) { Set(static_cast(inValue)); + } else { + Unimplement(); } } @@ -446,8 +486,10 @@ namespace Core { Set(Common::ToString(inValue)); } else if constexpr (Common::CppBool) { Set(inValue != 0); - } else { + } else if constexpr (Common::CppArithmetic) { Set(static_cast(inValue)); + } else { + Unimplement(); } } @@ -458,8 +500,10 @@ namespace Core { Set(Common::ToString(inValue)); } else if constexpr (Common::CppBool) { Set(inValue); - } else { + } else if constexpr (Common::CppArithmetic) { Set(inValue ? 1 : 0); + } else { + Unimplement(); } } @@ -470,8 +514,10 @@ namespace Core { Set(Common::ToString(inValue)); } else if constexpr (Common::CppBool) { Set(!Common::CompareNumber(inValue, 0.0f)); - } else { + } else if constexpr (Common::CppArithmetic) { Set(static_cast(inValue)); + } else { + Unimplement(); } } @@ -482,8 +528,10 @@ namespace Core { Set(Common::ToString(inValue)); } else if constexpr (Common::CppBool) { Set(!Common::CompareNumber(inValue, 0.0)); - } else { + } else if constexpr (Common::CppArithmetic) { Set(static_cast(inValue)); + } else { + Unimplement(); } } @@ -492,8 +540,10 @@ namespace Core { { if constexpr (Common::CppStdString) { Set(inValue); - } else { + } else if constexpr (Common::CppArithmetic) { Set(Common::ToArithmetic(inValue)); + } else { + Unimplement(); } } diff --git a/Engine/Source/Core/Include/Core/Thread.h b/Engine/Source/Core/Include/Core/Thread.h index b4cf64f7..782c69cc 100644 --- a/Engine/Source/Core/Include/Core/Thread.h +++ b/Engine/Source/Core/Include/Core/Thread.h @@ -21,7 +21,10 @@ namespace Core { class CORE_API ThreadContext { public: static void SetTag(ThreadTag inTag); - static ThreadTag GetTag(); + static void IncFrameNumber(); + + static ThreadTag Tag(); + static uint64_t FrameNumber(); static bool IsUnknownThread(); static bool IsGameThread(); static bool IsRenderThread(); diff --git a/Engine/Source/Core/Src/Console.cpp b/Engine/Source/Core/Src/Console.cpp index e6a017fa..9112f4e8 100644 --- a/Engine/Source/Core/Src/Console.cpp +++ b/Engine/Source/Core/Src/Console.cpp @@ -3,9 +3,36 @@ // #include +#include +#include #include +namespace Core::Internal { + static void SetConsoleSettingFromJsonValue(ConsoleSetting& inConsoleSetting, const rapidjson::Value& inJsonValue) + { + if (inJsonValue.IsInt()) { + inConsoleSetting.SetI32(inJsonValue.GetInt()); + } else if (inJsonValue.IsUint()) { + inConsoleSetting.SetU32(inJsonValue.GetUint()); + } else if (inJsonValue.IsInt64()) { + inConsoleSetting.SetI64(inJsonValue.GetInt64()); + } else if (inJsonValue.IsUint64()) { + inConsoleSetting.SetU64(inJsonValue.GetUint64()); + } else if (inJsonValue.IsBool()) { + inConsoleSetting.SetBool(inJsonValue.GetBool()); + } else if (inJsonValue.IsFloat()) { + inConsoleSetting.SetFloat(inJsonValue.GetFloat()); + } else if (inJsonValue.IsDouble()) { + inConsoleSetting.SetDouble(inJsonValue.GetDouble()); + } else if (inJsonValue.IsString()) { + inConsoleSetting.SetString(std::string(inJsonValue.GetString(), inJsonValue.GetStringLength())); + } else { + Unimplement(); + } + } +} + namespace Core { ConsoleSetting::ConsoleSetting(const std::string& inName, const std::string& inDescription, const CSFlags& inFlags) : name(inName) @@ -59,6 +86,40 @@ namespace Core { return *settings.at(inName); } + void Console::OverrideSettingsByConfig() const + { + std::vector paths; + paths.reserve(2); + paths.emplace_back(Paths::EngineConfigDir() / "ConsoleSettings.json"); + if (Paths::HasSetGameRoot()) { + paths.emplace_back(Paths::GameConfigDir() / "ConsoleSettings.json"); + } + + for (const auto& path : paths) { + if (!path.Exists()) { + continue; + } + + rapidjson::Document document = Common::FileUtils::ReadJsonFile(path.String()); + Assert(document.IsObject()); + + for (auto iter = document.MemberBegin(); iter != document.MemberEnd(); ++iter) { + const auto& nameJson = iter->name; + const auto nameString = std::string(nameJson.GetString(), nameJson.GetStringLength()); + if (!HasSetting(nameString)) { + continue; + } + + auto& consoleSetting = GetSetting(nameString); + if ((consoleSetting.Flags() & CSFlagBits::configOverridable) == CSFlags::null) { + continue; + } + + Internal::SetConsoleSettingFromJsonValue(consoleSetting, iter->value); + } + } + } + void Console::PerformRenderThreadSettingsCopy() const { for (const auto& setting : settings | std::views::values) { diff --git a/Engine/Source/Core/Src/Thread.cpp b/Engine/Source/Core/Src/Thread.cpp index 05fde0d8..e3a56b3a 100644 --- a/Engine/Source/Core/Src/Thread.cpp +++ b/Engine/Source/Core/Src/Thread.cpp @@ -6,17 +6,28 @@ namespace Core { static thread_local auto currentTag = ThreadTag::unknown; + static thread_local uint64_t frameNumber = 0; void ThreadContext::SetTag(ThreadTag inTag) { currentTag = inTag; } - ThreadTag ThreadContext::GetTag() + void ThreadContext::IncFrameNumber() + { + frameNumber++; + } + + ThreadTag ThreadContext::Tag() { return currentTag; } + uint64_t ThreadContext::FrameNumber() + { + return frameNumber; + } + bool ThreadContext::IsUnknownThread() { return currentTag == ThreadTag::unknown; @@ -54,7 +65,7 @@ namespace Core { ScopedThreadTag::ScopedThreadTag(ThreadTag inTag) { - tagToRestore = ThreadContext::GetTag(); + tagToRestore = ThreadContext::Tag(); ThreadContext::SetTag(inTag); } diff --git a/Engine/Source/Core/Test/ConsoleTest.cpp b/Engine/Source/Core/Test/ConsoleTest.cpp new file mode 100644 index 00000000..30922b01 --- /dev/null +++ b/Engine/Source/Core/Test/ConsoleTest.cpp @@ -0,0 +1,30 @@ +// +// Created by johnk on 2025/2/27. +// + +#include + +#include +#include + +static Core::ConsoleSettingValue csA("a", "", 1); +static Core::ConsoleSettingValue csB("b", "", true); +static Core::ConsoleSettingValue csC("c", "", "hello"); + +TEST(ConsoleTest, ConsoleSettingTest) +{ + Core::ScopedThreadTag tag(Core::ThreadTag::game); + + ASSERT_EQ(csA.Get(), 1); + ASSERT_TRUE(csB.Get()); + ASSERT_EQ(csC.Get(), "hello"); + + auto& console = Core::Console::Get(); + console.GetSetting("a").SetI32(2); + console.GetSetting("b").SetBool(false); + console.GetSetting("c").SetI32(1); + + ASSERT_EQ(csA.Get(), 2); + ASSERT_FALSE(csB.Get()); + ASSERT_EQ(csC.Get(), "1"); +} diff --git a/Engine/Source/Launch/Src/GameClient.cpp b/Engine/Source/Launch/Src/GameClient.cpp index 248e6b67..eadd1b7c 100644 --- a/Engine/Source/Launch/Src/GameClient.cpp +++ b/Engine/Source/Launch/Src/GameClient.cpp @@ -8,7 +8,7 @@ namespace Launch { GameClient::GameClient(GameViewport& inViewport) : viewport(inViewport) - , world("GameWorld", this) + , world("GameWorld", this, Runtime::PlayType::game) { } diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index ac0665eb..d07aff2e 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -420,6 +420,11 @@ namespace Mirror { static const Id moveCtor; }; + struct MIRROR_API MetaPresets { + static constexpr const auto* transient = "transient"; + static constexpr const auto* category = "category"; + }; + class MIRROR_API ReflNode { public: virtual ~ReflNode(); @@ -427,6 +432,7 @@ namespace Mirror { const Id& GetId() const; const std::string& GetName() const; const std::string& GetMeta(const std::string& key) const; + std::string GetMetaOr(const std::string& key, const std::string& defaultValue) const; std::string GetAllMeta() const; bool HasMeta(const std::string& key) const; bool GetMetaBool(const std::string& key) const; diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index ace19a66..a0787592 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -891,6 +891,11 @@ namespace Mirror { return iter->second; } + std::string ReflNode::GetMetaOr(const std::string& key, const std::string& defaultValue) const + { + return HasMeta(key) ? GetMeta(key) : defaultValue; + } + std::string ReflNode::GetAllMeta() const { std::stringstream stream; @@ -1259,7 +1264,7 @@ namespace Mirror { bool MemberVariable::IsTransient() const { - return GetMetaBoolOr("transient", false); + return GetMetaBoolOr(MetaPresets::transient, false); } MemberFunction::MemberFunction(ConstructParams&& params) @@ -1491,7 +1496,7 @@ namespace Mirror { std::vector result; result.reserve(classes.Size()); classes.Each([&](const Id& id, const Class& clazz) -> void { - if (clazz.HasMeta("category") && clazz.GetMeta("category") == category) { + if (clazz.GetMetaOr(MetaPresets::category, "") == category) { result.emplace_back(&clazz); } }); @@ -1505,28 +1510,28 @@ namespace Mirror { void Class::ForEachStaticVariable(const VariableTraverser& func) const { - for (const auto& [id, variable] : staticVariables) { + for (const auto& variable : staticVariables | std::views::values) { func(variable); } } void Class::ForEachStaticFunction(const FunctionTraverser& func) const { - for (const auto& [id, function] : staticFunctions) { + for (const auto& function : staticFunctions | std::views::values) { func(function); } } void Class::ForEachMemberVariable(const MemberVariableTraverser& func) const { - for (const auto& [id, memberVariable] : memberVariables) { + for (const auto& memberVariable : memberVariables | std::views::values) { func(memberVariable); } } void Class::ForEachMemberFunction(const MemberFunctionTraverser& func) const { - for (const auto& [id, memberFunction] : memberFunctions) { + for (const auto& memberFunction : memberFunctions | std::views::values) { func(memberFunction); } } @@ -1815,7 +1820,7 @@ namespace Mirror { bool Class::IsTransient() const { - return GetMetaBoolOr("transient", false); + return GetMetaBoolOr(MetaPresets::transient, false); } EnumValue::EnumValue(ConstructParams&& inParams) diff --git a/Engine/Source/RHI-DirectX12/Src/CommandRecorder.cpp b/Engine/Source/RHI-DirectX12/Src/CommandRecorder.cpp index 705ddaff..f60285cf 100644 --- a/Engine/Source/RHI-DirectX12/Src/CommandRecorder.cpp +++ b/Engine/Source/RHI-DirectX12/Src/CommandRecorder.cpp @@ -359,6 +359,16 @@ namespace RHI::DirectX12 { const auto* buffer = static_cast(inBarrier.buffer.pointer); Assert(buffer); resource = buffer->GetNative(); + + D3D12_HEAP_PROPERTIES heapProperties; + D3D12_HEAP_FLAGS heapFlags; + Assert(SUCCEEDED(resource->GetHeapProperties(&heapProperties, &heapFlags))); + + // validation layer: upload heap can not be transited + if (heapProperties.Type == D3D12_HEAP_TYPE_UPLOAD) { + return; + } + beforeState = EnumCast(inBarrier.buffer.before); afterState = EnumCast(inBarrier.buffer.after); } else { diff --git a/Engine/Source/RHI/Include/RHI/Buffer.h b/Engine/Source/RHI/Include/RHI/Buffer.h index 80ceec45..f4d7443c 100644 --- a/Engine/Source/RHI/Include/RHI/Buffer.h +++ b/Engine/Source/RHI/Include/RHI/Buffer.h @@ -26,6 +26,8 @@ namespace RHI { BufferCreateInfo& SetInitialState(BufferState inState); BufferCreateInfo& SetDebugName(std::string inDebugName); + uint64_t Hash() const; + bool operator==(const BufferCreateInfo& rhs) const; }; diff --git a/Engine/Source/RHI/Include/RHI/BufferView.h b/Engine/Source/RHI/Include/RHI/BufferView.h index c64a7df1..264bce3d 100644 --- a/Engine/Source/RHI/Include/RHI/BufferView.h +++ b/Engine/Source/RHI/Include/RHI/BufferView.h @@ -49,7 +49,7 @@ namespace RHI { BufferViewCreateInfo& SetExtendIndex(IndexFormat inFormat); BufferViewCreateInfo& SetExtendStorage(uint32_t inStride); - size_t Hash() const; + uint64_t Hash() const; }; class BufferView { diff --git a/Engine/Source/RHI/Include/RHI/Pipeline.h b/Engine/Source/RHI/Include/RHI/Pipeline.h index 0747e388..1e58a2b1 100644 --- a/Engine/Source/RHI/Include/RHI/Pipeline.h +++ b/Engine/Source/RHI/Include/RHI/Pipeline.h @@ -108,7 +108,7 @@ namespace RHI { PrimitiveState& SetFrontFace(FrontFace inFrontFace); PrimitiveState& SetCullMode(CullMode inCullMode); PrimitiveState& SetDepthClip(bool inDepthClip); - size_t Hash() const; + uint64_t Hash() const; }; struct StencilFaceState { @@ -161,7 +161,7 @@ namespace RHI { DepthStencilState& SetDepthBias(int32_t inDepthBias); DepthStencilState& SetDepthBiasSlopeScale(float inDepthBiasSlopeScale); DepthStencilState& SetDepthBiasClamp(float inDepthBiasClamp); - size_t Hash() const; + uint64_t Hash() const; }; struct MultiSampleState { @@ -177,7 +177,7 @@ namespace RHI { MultiSampleState& SetCount(uint8_t inCount); MultiSampleState& SetMask(uint32_t inMask); MultiSampleState& SetAlphaToCoverage(bool inAlphaToCoverage); - size_t Hash() const; + uint64_t Hash() const; }; struct BlendComponent { @@ -210,7 +210,7 @@ namespace RHI { ColorTargetState& SetBlendEnabled(bool inBlendEnabled); ColorTargetState& SetColorBlend(const BlendComponent& inColorBlend); ColorTargetState& SetAlphaBlend(const BlendComponent& inAlphaBlend); - size_t Hash() const; + uint64_t Hash() const; }; struct FragmentState { @@ -218,7 +218,7 @@ namespace RHI { FragmentState(); FragmentState& AddColorTarget(const ColorTargetState& inState); - size_t Hash() const; + uint64_t Hash() const; }; struct ComputePipelineCreateInfo { diff --git a/Engine/Source/RHI/Include/RHI/Texture.h b/Engine/Source/RHI/Include/RHI/Texture.h index 132a4062..2f3551d5 100644 --- a/Engine/Source/RHI/Include/RHI/Texture.h +++ b/Engine/Source/RHI/Include/RHI/Texture.h @@ -37,6 +37,8 @@ namespace RHI { TextureCreateInfo& SetInitialState(TextureState inState); TextureCreateInfo& SetDebugName(std::string inDebugName); + uint64_t Hash() const; + bool operator==(const TextureCreateInfo& rhs) const; }; diff --git a/Engine/Source/RHI/Include/RHI/TextureView.h b/Engine/Source/RHI/Include/RHI/TextureView.h index 98fdc8f8..b23a253f 100644 --- a/Engine/Source/RHI/Include/RHI/TextureView.h +++ b/Engine/Source/RHI/Include/RHI/TextureView.h @@ -33,7 +33,7 @@ namespace RHI { TextureViewCreateInfo& SetMipLevels(uint8_t inBaseMipLevel, uint8_t inMipLevelNum); TextureViewCreateInfo& SetArrayLayers(uint8_t inBaseArrayLayer, uint8_t inArrayLayerNum); - size_t Hash() const; + uint64_t Hash() const; }; class TextureView { diff --git a/Engine/Source/RHI/Src/Buffer.cpp b/Engine/Source/RHI/Src/Buffer.cpp index 21614ea6..88b493ad 100644 --- a/Engine/Source/RHI/Src/Buffer.cpp +++ b/Engine/Source/RHI/Src/Buffer.cpp @@ -37,10 +37,21 @@ namespace RHI { return *this; } + uint64_t BufferCreateInfo::Hash() const + { + const std::vector values = { + size, + static_cast(usages.Value()), + static_cast(initialState), + }; + return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); + } + bool BufferCreateInfo::operator==(const BufferCreateInfo& rhs) const { return size == rhs.size - && usages == rhs.usages; + && usages == rhs.usages + && initialState == rhs.initialState; } Buffer::Buffer(const BufferCreateInfo& inCreateInfo) diff --git a/Engine/Source/RHI/Src/BufferView.cpp b/Engine/Source/RHI/Src/BufferView.cpp index 0be38cdd..6402f76c 100644 --- a/Engine/Source/RHI/Src/BufferView.cpp +++ b/Engine/Source/RHI/Src/BufferView.cpp @@ -64,12 +64,11 @@ namespace RHI { BufferViewCreateInfo& BufferViewCreateInfo::SetExtendStorage(uint32_t inStride) { - extend = StorageBufferViewInfo { inStride }; + extend = StorageBufferViewInfo {inStride}; return *this; } - - size_t BufferViewCreateInfo::Hash() const + uint64_t BufferViewCreateInfo::Hash() const { return Common::HashUtils::CityHash(this, sizeof(BufferViewCreateInfo)); } diff --git a/Engine/Source/RHI/Src/Pipeline.cpp b/Engine/Source/RHI/Src/Pipeline.cpp index cdb50367..399bbd4a 100644 --- a/Engine/Source/RHI/Src/Pipeline.cpp +++ b/Engine/Source/RHI/Src/Pipeline.cpp @@ -112,7 +112,7 @@ namespace RHI { return *this; } - size_t PrimitiveState::Hash() const + uint64_t PrimitiveState::Hash() const { return Common::HashUtils::CityHash(this, sizeof(PrimitiveState)); } @@ -221,7 +221,7 @@ namespace RHI { return *this; } - size_t DepthStencilState::Hash() const + uint64_t DepthStencilState::Hash() const { return Common::HashUtils::CityHash(this, sizeof(DepthStencilState)); } @@ -251,7 +251,7 @@ namespace RHI { return *this; } - size_t MultiSampleState::Hash() const + uint64_t MultiSampleState::Hash() const { return Common::HashUtils::CityHash(this, sizeof(MultiSampleState)); } @@ -307,7 +307,7 @@ namespace RHI { return *this; } - size_t ColorTargetState::Hash() const + uint64_t ColorTargetState::Hash() const { return Common::HashUtils::CityHash(this, sizeof(ColorTargetState)); } @@ -322,15 +322,15 @@ namespace RHI { return *this; } - size_t FragmentState::Hash() const + uint64_t FragmentState::Hash() const { - std::vector values; + std::vector values; values.reserve(colorTargets.size()); for (const auto& colorTarget : colorTargets) { values.emplace_back(colorTarget.Hash()); } - return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(size_t)); + return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); } ComputePipelineCreateInfo::ComputePipelineCreateInfo() diff --git a/Engine/Source/RHI/Src/Texture.cpp b/Engine/Source/RHI/Src/Texture.cpp index 0464678d..e9674a6b 100644 --- a/Engine/Source/RHI/Src/Texture.cpp +++ b/Engine/Source/RHI/Src/Texture.cpp @@ -78,6 +78,22 @@ namespace RHI { return *this; } + uint64_t TextureCreateInfo::Hash() const + { + const std::vector values = { + static_cast(dimension), + static_cast(width), + static_cast(height), + static_cast(depthOrArraySize), + static_cast(format), + static_cast(usages.Value()), + static_cast(mipLevels), + static_cast(samples), + static_cast(initialState), + }; + return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); + } + bool TextureCreateInfo::operator==(const TextureCreateInfo& rhs) const { return dimension == rhs.dimension diff --git a/Engine/Source/RHI/Src/TextureView.cpp b/Engine/Source/RHI/Src/TextureView.cpp index 491ea0d2..afb0423a 100644 --- a/Engine/Source/RHI/Src/TextureView.cpp +++ b/Engine/Source/RHI/Src/TextureView.cpp @@ -55,7 +55,7 @@ namespace RHI { return *this; } - size_t TextureViewCreateInfo::Hash() const + uint64_t TextureViewCreateInfo::Hash() const { return Common::HashUtils::CityHash(this, sizeof(TextureViewCreateInfo)); } diff --git a/Engine/Source/Render/Include/Render/RenderCache.h b/Engine/Source/Render/Include/Render/RenderCache.h index 2bbb1430..03ef601e 100644 --- a/Engine/Source/Render/Include/Render/RenderCache.h +++ b/Engine/Source/Render/Include/Render/RenderCache.h @@ -30,7 +30,7 @@ namespace Render { std::string FinalSemantic() const; RHI::PlatformVertexBinding GetRHI(const Render::ShaderReflectionData& inReflectionData) const; - size_t Hash() const; + uint64_t Hash() const; }; struct RVertexAttribute : RHI::VertexAttributeBase { @@ -43,7 +43,7 @@ namespace Render { RHI::VertexAttribute GetRHI(const Render::ShaderReflectionData& inReflectionData) const; RVertexAttribute& SetBinding(const RVertexBinding& inBinding); - size_t Hash() const; + uint64_t Hash() const; }; struct RVertexBufferLayout : RHI::VertexBufferLayoutBase { @@ -55,7 +55,7 @@ namespace Render { RHI::VertexBufferLayout GetRHI(const Render::ShaderReflectionData& inReflectionData) const; RVertexBufferLayout& AddAttribute(const RVertexAttribute& inAttribute); - size_t Hash() const; + uint64_t Hash() const; }; struct RVertexState { @@ -65,7 +65,7 @@ namespace Render { RHI::VertexState GetRHI(const Render::ShaderReflectionData& inReflectionData) const; RVertexState& AddVertexBufferLayout(const RVertexBufferLayout& inLayout); - size_t Hash() const; + uint64_t Hash() const; }; struct BindGroupLayoutDesc { @@ -76,7 +76,7 @@ namespace Render { struct ComputePipelineShaderSet { Render::ShaderInstance computeShader; - size_t Hash() const; + uint64_t Hash() const; }; struct RasterPipelineShaderSet { @@ -86,19 +86,19 @@ namespace Render { Render::ShaderInstance domainShader; Render::ShaderInstance hullShader; - size_t Hash() const; + uint64_t Hash() const; }; struct ComputePipelineLayoutDesc { ComputePipelineShaderSet shaders; - size_t Hash() const; + uint64_t Hash() const; }; struct RasterPipelineLayoutDesc { RasterPipelineShaderSet shaders; - size_t Hash() const; + uint64_t Hash() const; }; template concept AnyPipelineLayoutDesc = std::is_same_v || std::is_same_v; @@ -106,7 +106,7 @@ namespace Render { struct ComputePipelineStateDesc { ComputePipelineShaderSet shaders; - size_t Hash() const; + uint64_t Hash() const; }; struct RasterPipelineStateDesc { @@ -128,7 +128,7 @@ namespace Render { RasterPipelineStateDesc& SetDepthStencilState(const RDepthStencilState& inDepthStencilState); RasterPipelineStateDesc& SetMultiSampleState(const RMultiSampleState& inMultiSampleState); RasterPipelineStateDesc& SetFragmentState(const RFragmentState& inFragmentState); - size_t Hash() const; + uint64_t Hash() const; }; class Sampler { @@ -262,17 +262,47 @@ namespace Render { static ResourceViewCache& Get(RHI::Device& device); ~ResourceViewCache(); - void Invalidate(); - void Invalidate(RHI::Buffer* buffer); - void Invalidate(RHI::Texture* texture); RHI::BufferView* GetOrCreate(RHI::Buffer* buffer, const RHI::BufferViewCreateInfo& inDesc); RHI::TextureView* GetOrCreate(RHI::Texture* texture, const RHI::TextureViewCreateInfo& inDesc); + void Invalidate(RHI::Buffer* buffer); + void Invalidate(RHI::Texture* texture); + void Forfeit(); private: explicit ResourceViewCache(RHI::Device& inDevice); + struct BufferViewCache { + bool valid; + uint64_t lastUsedFrame; + std::unordered_map> views; + }; + + struct TextureViewCache { + bool valid; + uint64_t lastUsedFrame; + std::unordered_map> views; + }; + + RHI::Device& device; + std::unordered_map bufferViewCaches; + std::unordered_map textureViewCaches; + }; + + class BindGroupCache { + public: + static BindGroupCache& Get(RHI::Device& device); + ~BindGroupCache(); + + RHI::BindGroup* Allocate(const RHI::BindGroupCreateInfo& inCreateInfo); + void Invalidate(); + void Forfeit(); + + private: + using AllocateFrameNumber = uint64_t; + + explicit BindGroupCache(RHI::Device& inDevice); + RHI::Device& device; - std::unordered_map>> bufferViews; - std::unordered_map>> textureViews; + std::vector, AllocateFrameNumber>> bindGroups; }; } diff --git a/Engine/Source/Render/Include/Render/RenderGraph.h b/Engine/Source/Render/Include/Render/RenderGraph.h index 412b2c67..cf4c6c83 100644 --- a/Engine/Source/Render/Include/Render/RenderGraph.h +++ b/Engine/Source/Render/Include/Render/RenderGraph.h @@ -416,7 +416,7 @@ namespace Render { std::vector asyncTimelineExecuteContexts; std::unordered_map> devirtualizedResources; std::unordered_map> devirtualizedResourceViews; - std::unordered_map> devirtualizedBindGroups; + std::unordered_map devirtualizedBindGroups; std::vector> bufferUploadTasks; }; } diff --git a/Engine/Source/Render/Include/Render/RenderModule.h b/Engine/Source/Render/Include/Render/RenderModule.h index 83a78f1e..f46a0ca7 100644 --- a/Engine/Source/Render/Include/Render/RenderModule.h +++ b/Engine/Source/Render/Include/Render/RenderModule.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include #include @@ -30,8 +29,9 @@ namespace Render { void DeInitialize(); RHI::Device* GetDevice() const; Render::RenderThread& GetRenderThread() const; - Common::UniquePtr NewScene(); - Common::UniquePtr NewView(); + Scene* NewScene() const; + ViewState* NewViewState() const; + View CreateView() const; private: bool initialized; diff --git a/Engine/Source/Render/Include/Render/RenderThread.h b/Engine/Source/Render/Include/Render/RenderThread.h index fd8725d2..6deb77c2 100644 --- a/Engine/Source/Render/Include/Render/RenderThread.h +++ b/Engine/Source/Render/Include/Render/RenderThread.h @@ -58,10 +58,9 @@ namespace Render { using RetType = std::invoke_result_t; Assert(threads != nullptr); - auto packedTask = std::bind(std::forward(inTask)); - return threads->EmplaceTask([packedTask]() -> RetType { + return threads->EmplaceTask([inTask]() -> RetType { Core::ScopedThreadTag tag(Core::ThreadTag::renderWorker); - return packedTask(); + return inTask(); }); } @@ -69,10 +68,10 @@ namespace Render { void RenderWorkerThreads::ExecuteTasks(size_t inTaskNum, F&& inTask) { Assert(threads != nullptr); - auto packedTask = std::bind(std::forward(inTask), std::placeholders::_1); - threads->ExecuteTasks(inTaskNum, [packedTask](size_t inIndex) -> void { + auto reboundTask = std::bind(std::forward(inTask), std::placeholders::_1); + threads->ExecuteTasks(inTaskNum, [reboundTask](size_t inIndex) -> void { Core::ScopedThreadTag tag(Core::ThreadTag::renderWorker); - packedTask(inIndex); + reboundTask(inIndex); }); } } diff --git a/Engine/Source/Render/Include/Render/Renderer.h b/Engine/Source/Render/Include/Render/Renderer.h index 167ea006..50fd671a 100644 --- a/Engine/Source/Render/Include/Render/Renderer.h +++ b/Engine/Source/Render/Include/Render/Renderer.h @@ -18,8 +18,9 @@ namespace Render { public: struct Params { const Scene* scene; + Common::UVec2 surfaceExtent; const RHI::Texture* surface; - std::vector views; + std::vector views; RHI::Semaphore* waitSemaphore; RHI::Semaphore* signalSemaphore; RHI::Fence* signalFence; @@ -33,7 +34,7 @@ namespace Render { protected: const Scene* scene; const RHI::Texture* surface; - std::vector views; + std::vector views; RHI::Semaphore* waitSemaphore; RHI::Semaphore* signalSemaphore; RHI::Fence* signalFence; @@ -48,6 +49,4 @@ namespace Render { private: }; - - // TODO ScriptableRenderer } diff --git a/Engine/Source/Render/Include/Render/ResourcePool.h b/Engine/Source/Render/Include/Render/ResourcePool.h index 5b592017..4d2ba003 100644 --- a/Engine/Source/Render/Include/Render/ResourcePool.h +++ b/Engine/Source/Render/Include/Render/ResourcePool.h @@ -7,10 +7,14 @@ #include #include -#include #include +#include #include +namespace Render::Internal { + constexpr uint64_t pooledResourceReleaseFrameLatency = 2; +} + namespace Render { template struct RHIResTraits {}; @@ -25,10 +29,13 @@ namespace Render { RHIRes* GetRHI() const; const DescType& GetDesc() const; + uint64_t LastUsedFrame() const; + void MarkUsedThisFrame(); private: Common::UniquePtr rhiHandle; DescType desc; + uint64_t lastUsedFrame; }; using PooledBuffer = PooledResource; @@ -51,13 +58,14 @@ namespace Render { ResRefType Allocate(const DescType& desc); size_t Size() const; - void Tick(); + void Forfeit(); + void Invalidate(); private: explicit ResourcePool(RHI::Device& inDevice); RHI::Device& device; - std::vector> pooledResourceAndAges; + std::vector pooledResources; }; using BufferPool = ResourcePool; @@ -79,6 +87,7 @@ namespace Render { PooledResource::PooledResource(Common::UniquePtr&& inRhiHandle, DescType inDesc) : rhiHandle(std::move(inRhiHandle)) , desc(std::move(inDesc)) + , lastUsedFrame(Core::ThreadContext::FrameNumber()) { } @@ -97,6 +106,18 @@ namespace Render { return desc; } + template + uint64_t PooledResource::LastUsedFrame() const + { + return lastUsedFrame; + } + + template + void PooledResource::MarkUsedThisFrame() + { + lastUsedFrame = Core::ThreadContext::FrameNumber(); + } + template <> struct PooledResTraits { using ResType = PooledBuffer; @@ -140,41 +161,52 @@ namespace Render { template typename ResourcePool::ResRefType ResourcePool::Allocate(const DescType& desc) { - for (auto& [pooledResource, age] : pooledResourceAndAges) { + for (auto& pooledResource : pooledResources) { if (pooledResource.RefCount() == 1 && desc == pooledResource->GetDesc()) { - age = 0; + pooledResource->MarkUsedThisFrame(); return pooledResource; } } auto result = PooledResTraits::CreateResource(device, desc); - pooledResourceAndAges.emplace_back(result, 0); + pooledResources.emplace_back(result); return result; } template size_t ResourcePool::Size() const { - return pooledResourceAndAges.size(); + return pooledResources.size(); } template - void ResourcePool::Tick() + void ResourcePool::Forfeit() { - for (auto i = 0; i < pooledResourceAndAges.size();) { + const auto currentFrame = Core::ThreadContext::FrameNumber(); + + for (auto i = 0; i < pooledResources.size();) { bool needRelease = false; - auto& [pooledResource, age] = pooledResourceAndAges[i]; + auto& pooledResource = pooledResources[i]; if (pooledResource.RefCount() <= 1) { - needRelease = ++age >= 2; + needRelease = currentFrame - pooledResource->LastUsedFrame() > Internal::pooledResourceReleaseFrameLatency; } else { - age = 0; + pooledResource->MarkUsedThisFrame(); } if (needRelease) { // NOLINT - pooledResourceAndAges.erase(pooledResourceAndAges.begin() + i); + pooledResources.erase(pooledResources.begin() + i); } else { i++; } } } -} + + template + void ResourcePool::Invalidate() + { + for (const auto& pooledResource : pooledResources) { + Assert(pooledResource.RefCount() == 1); + } + pooledResources.clear(); + } +} // namespace Render diff --git a/Engine/Source/Render/Include/Render/Scene.h b/Engine/Source/Render/Include/Render/Scene.h index 04b0a990..d2cbb599 100644 --- a/Engine/Source/Render/Include/Render/Scene.h +++ b/Engine/Source/Render/Include/Render/Scene.h @@ -4,30 +4,92 @@ #pragma once -#include +#include +#include #include namespace Render { - template using SPPool = Common::TrunkList; - template using SPHandle = typename SPPool::Handle; - - using LightSPPool = SPPool; - using LightSPH = SPHandle; - - // scene only store render thread cpu data copy, gpu data will auto created by render graph and managed by resource pool + // Render::Scene is a container of render-thread world data copy. + // Notice all operations to scene need be down in render-thread. class Scene final { public: + using EntityId = uint32_t; + Scene(); ~Scene(); NonCopyable(Scene) NonMovable(Scene) - LightSPH AddLight(); - void UpdateLight(const LightSPH& inHandle); - void RemoveLight(const LightSPH& inHandle); + template void Add(EntityId inEntity, SP&& inSceneProxy); + template SP& Get(EntityId inEntity); + template const SP& Get(EntityId inEntity) const; + template void Remove(EntityId inEntity); private: - LightSPPool lights; + template using SceneProxyContainer = std::unordered_map; + + template SceneProxyContainer& GetSceneProxyContainer(); + template const SceneProxyContainer& GetSceneProxyContainer() const; + + SceneProxyContainer lightSceneProxies; }; } + +namespace Render { + template + void Scene::Add(EntityId inEntity, SP&& inSceneProxy) + { + Assert(Core::ThreadContext::IsRenderThread()); + GetSceneProxyContainer().emplace(inEntity, std::move(inSceneProxy)); // NOLINT + } + + template + SP& Scene::Get(EntityId inEntity) + { + Assert(Core::ThreadContext::IsRenderThread()); + return GetSceneProxyContainer().at(inEntity); + } + + template + const SP& Scene::Get(EntityId inEntity) const + { + Assert(Core::ThreadContext::IsRenderThread()); + return GetSceneProxyContainer().at(inEntity); + } + + template + void Scene::Remove(EntityId inEntity) + { + Assert(Core::ThreadContext::IsRenderThread()); + GetSceneProxyContainer().erase(inEntity); + } + + template + Scene::SceneProxyContainer& Scene::GetSceneProxyContainer() + { + Unimplement(); + return *static_cast*>(nullptr); // NOLINT + } + + template + const Scene::SceneProxyContainer& Scene::GetSceneProxyContainer() const + { + Unimplement(); + return *static_cast*>(nullptr); // NOLINT + } +} + +namespace Render { + template <> + inline Scene::SceneProxyContainer& Scene::GetSceneProxyContainer() + { + return lightSceneProxies; + } + + template <> + inline const Scene::SceneProxyContainer& Scene::GetSceneProxyContainer() const + { + return lightSceneProxies; + } +} diff --git a/Engine/Source/Render/Include/Render/SceneProxy/Light.h b/Engine/Source/Render/Include/Render/SceneProxy/Light.h index 40977e46..8a2e32b6 100644 --- a/Engine/Source/Render/Include/Render/SceneProxy/Light.h +++ b/Engine/Source/Render/Include/Render/SceneProxy/Light.h @@ -4,8 +4,6 @@ #pragma once -#include - #include #include @@ -18,6 +16,8 @@ namespace Render { }; struct LightSceneProxy { + LightSceneProxy(); + LightType type; Common::FMat4x4 localToWorld; Common::Color color; @@ -26,3 +26,14 @@ namespace Render { float radius; }; } + +namespace Render { + inline LightSceneProxy::LightSceneProxy() + : type(LightType::max) + , localToWorld(Common::FMat4x4Consts::identity) + , color(Common::ColorConsts::white) + , intensity(0.0f) + , radius(0.0f) + { + } +} diff --git a/Engine/Source/Render/Include/Render/Shader.h b/Engine/Source/Render/Include/Render/Shader.h index fcf5bced..991208f7 100644 --- a/Engine/Source/Render/Include/Render/Shader.h +++ b/Engine/Source/Render/Include/Render/Shader.h @@ -71,7 +71,7 @@ namespace Render { const ShaderReflectionData* reflectionData = nullptr; bool IsValid() const; - size_t Hash() const; + uint64_t Hash() const; }; using ShaderArchivePackage = std::unordered_map; @@ -164,7 +164,7 @@ namespace Render { const std::vector& GetShaderTypes() const; // call this func before device release - void InvalidateAll() const; + void Invalidate() const; // call this func after shader reloaded void ReloadAll() const; diff --git a/Engine/Source/Render/Include/Render/View.h b/Engine/Source/Render/Include/Render/View.h index acff73c6..0a5efc25 100644 --- a/Engine/Source/Render/Include/Render/View.h +++ b/Engine/Source/Render/Include/Render/View.h @@ -4,26 +4,30 @@ #pragma once -#include -#include #include #include namespace Render { - class View { - public: - View(); - ~View(); - - NonCopyable(View) - NonMovable(View) - - void Update(const Common::FMat4x4& inViewMatrix, const Common::FMat4x4& inProjectionMatrix, const Common::FRect& inViewport); + struct ViewRenderData { + ViewRenderData(); - private: Common::FMat4x4 viewMatrix; Common::FMat4x4 projectionMatrix; Common::FRect viewport; - // TODO viewOrigin, etc... + }; + + struct ViewState { + ViewState(); + + ViewRenderData prevViewRenderData; + // TODO frame number ... + // TODO temporal history ... + }; + + struct View { + View(); + + ViewRenderData renderData; + ViewState* viewState; }; } diff --git a/Engine/Source/Render/SharedSrc/RenderModule.cpp b/Engine/Source/Render/SharedSrc/RenderModule.cpp index b37ff2c8..deb508af 100644 --- a/Engine/Source/Render/SharedSrc/RenderModule.cpp +++ b/Engine/Source/Render/SharedSrc/RenderModule.cpp @@ -67,14 +67,19 @@ namespace Render { return RenderThread::Get(); } - Common::UniquePtr RenderModule::NewScene() // NOLINT + Scene* RenderModule::NewScene() const // NOLINT { return new Scene(); } - Common::UniquePtr RenderModule::NewView() // NOLINT + ViewState* RenderModule::NewViewState() const // NOLINT { - return new View(); + return new ViewState(); + } + + View RenderModule::CreateView() const // NOLINT + { + return View(); } } diff --git a/Engine/Source/Render/Src/RenderCache.cpp b/Engine/Source/Render/Src/RenderCache.cpp index ce68b024..6fc80556 100644 --- a/Engine/Source/Render/Src/RenderCache.cpp +++ b/Engine/Source/Render/Src/RenderCache.cpp @@ -7,6 +7,12 @@ #include #include +#include + +namespace Render::Internal { + constexpr uint64_t resourceViewCacheReleaseFrameLatency = 2; + constexpr uint64_t bindGroupCacheReleaseFrameLatency = 2; +} namespace Render { class PipelineLayoutCache { @@ -84,14 +90,14 @@ namespace Render { return inReflectionData.QueryVertexBindingChecked(FinalSemantic()); } - size_t RVertexBinding::Hash() const + uint64_t RVertexBinding::Hash() const { // NOTICE: string can not use city hash for this ptr, cause can be change every time allocated - const std::vector values = { + const std::vector values = { Common::HashUtils::CityHash(semanticName.data(), semanticName.size()), - static_cast(semanticIndex) + static_cast(semanticIndex) }; - return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(size_t)); + return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); } RVertexAttribute::RVertexAttribute(const RVertexBinding& inBinding, RHI::VertexFormat inFormat, size_t inOffset) @@ -106,14 +112,14 @@ namespace Render { return *this; } - size_t RVertexAttribute::Hash() const + uint64_t RVertexAttribute::Hash() const { - const std::vector values = { + const std::vector values = { binding.Hash(), - static_cast(format), + static_cast(format), offset }; - return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(size_t)); + return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); } RHI::VertexAttribute RVertexAttribute::GetRHI(const Render::ShaderReflectionData& inReflectionData) const @@ -142,15 +148,15 @@ namespace Render { return *this; } - size_t RVertexBufferLayout::Hash() const + uint64_t RVertexBufferLayout::Hash() const { - std::vector values; + std::vector values; values.reserve(attributes.size()); for (const auto& attribute : attributes) { values.emplace_back(attribute.Hash()); } - return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(size_t)); + return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); } RVertexState::RVertexState() = default; @@ -171,45 +177,45 @@ namespace Render { return *this; } - size_t RVertexState::Hash() const + uint64_t RVertexState::Hash() const { - std::vector values; + std::vector values; values.reserve(bufferLayouts.size()); for (const auto& layout : bufferLayouts) { values.emplace_back(layout.Hash()); } - return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(size_t)); + return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); } - size_t ComputePipelineShaderSet::Hash() const + uint64_t ComputePipelineShaderSet::Hash() const { return computeShader.Hash(); } - size_t RasterPipelineShaderSet::Hash() const + uint64_t RasterPipelineShaderSet::Hash() const { - const std::vector values = { + const std::vector values = { vertexShader.Hash(), pixelShader.Hash(), geometryShader.Hash(), domainShader.Hash(), hullShader.Hash() }; - return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(size_t)); + return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); } - size_t ComputePipelineLayoutDesc::Hash() const + uint64_t ComputePipelineLayoutDesc::Hash() const { return shaders.Hash(); } - size_t RasterPipelineLayoutDesc::Hash() const + uint64_t RasterPipelineLayoutDesc::Hash() const { return shaders.Hash(); } - size_t ComputePipelineStateDesc::Hash() const + uint64_t ComputePipelineStateDesc::Hash() const { return shaders.Hash(); } @@ -276,9 +282,9 @@ namespace Render { return *this; } - size_t RasterPipelineStateDesc::Hash() const + uint64_t RasterPipelineStateDesc::Hash() const { - const std::vector values = { + const std::vector values = { shaders.Hash(), vertexState.Hash(), primitiveState.Hash(), @@ -286,7 +292,7 @@ namespace Render { multiSampleState.Hash(), fragmentState.Hash() }; - return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(size_t)); + return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); } Sampler::Sampler(RHI::Device& inDevice, const RSamplerDesc& inDesc) @@ -588,49 +594,112 @@ namespace Render { ResourceViewCache::~ResourceViewCache() = default; - void ResourceViewCache::Invalidate() + RHI::BufferView* ResourceViewCache::GetOrCreate(RHI::Buffer* buffer, const RHI::BufferViewCreateInfo& inDesc) { - bufferViews.clear(); - textureViews.clear(); + auto& views = bufferViewCaches[buffer].views; + + auto hash = inDesc.Hash(); + if (const auto iter = views.find(hash); + iter == views.end()) { + views.emplace(std::make_pair(hash, Common::UniquePtr(buffer->CreateBufferView(inDesc)))); + } + return views.at(hash).Get(); + } + + RHI::TextureView* ResourceViewCache::GetOrCreate(RHI::Texture* texture, const RHI::TextureViewCreateInfo& inDesc) + { + auto& views = textureViewCaches[texture].views; + + auto hash = inDesc.Hash(); + if (const auto iter = views.find(hash); + iter == views.end()) { + views.emplace(std::make_pair(hash, Common::UniquePtr(texture->CreateTextureView(inDesc)))); + } + return views.at(hash).Get(); } void ResourceViewCache::Invalidate(RHI::Buffer* buffer) // NOLINT { - if (const auto iter = bufferViews.find(buffer); - iter != bufferViews.end()) { - iter->second.clear(); + if (const auto iter = bufferViewCaches.find(buffer); + iter != bufferViewCaches.end()) { + iter->second.valid = false; } } void ResourceViewCache::Invalidate(RHI::Texture* texture) // NOLINT { - if (const auto iter = textureViews.find(texture); - iter != textureViews.end()) { - iter->second.clear(); + if (const auto iter = textureViewCaches.find(texture); + iter != textureViewCaches.end()) { + iter->second.valid = false; } } - RHI::BufferView* ResourceViewCache::GetOrCreate(RHI::Buffer* buffer, const RHI::BufferViewCreateInfo& inDesc) + void ResourceViewCache::Forfeit() { - auto& views = bufferViews[buffer]; + const auto forfeitCaches = [](auto& caches) -> void { // NOLINT + const auto currentFrameNumber = Core::ThreadContext::FrameNumber(); - auto hash = inDesc.Hash(); - if (const auto iter = views.find(hash); - iter == views.end()) { - views.emplace(std::make_pair(hash, Common::UniquePtr(buffer->CreateBufferView(inDesc)))); + std::vector::key_type> resourcesToRelease; + resourcesToRelease.reserve(caches.size()); + + for (auto& [resource, cache] : caches) { + auto& [valid, lastUsedFrame, views] = cache; + + if (valid) { + lastUsedFrame = currentFrameNumber; + } else if (currentFrameNumber - lastUsedFrame > Internal::resourceViewCacheReleaseFrameLatency) { + resourcesToRelease.emplace_back(resource); + } + } + + for (auto* resourceToRelease : resourcesToRelease) { + caches.erase(resourceToRelease); + } + }; + + forfeitCaches(bufferViewCaches); + forfeitCaches(textureViewCaches); + } + + BindGroupCache& BindGroupCache::Get(RHI::Device& device) + { + static std::unordered_map> map; + + if (!map.contains(&device)) { + map.emplace(std::make_pair(&device, Common::UniquePtr(new BindGroupCache(device)))); } - return views.at(hash).Get(); + return *map.at(&device); } - RHI::TextureView* ResourceViewCache::GetOrCreate(RHI::Texture* texture, const RHI::TextureViewCreateInfo& inDesc) + BindGroupCache::~BindGroupCache() = default; + + RHI::BindGroup* BindGroupCache::Allocate(const RHI::BindGroupCreateInfo& inCreateInfo) { - auto& views = textureViews[texture]; + const auto& [ptr, frameNumber] = bindGroups.emplace_back(device.CreateBindGroup(inCreateInfo), Core::ThreadContext::FrameNumber()); + return ptr.Get(); + } - auto hash = inDesc.Hash(); - if (const auto iter = views.find(hash); - iter == views.end()) { - views.emplace(std::make_pair(hash, Common::UniquePtr(texture->CreateTextureView(inDesc)))); + void BindGroupCache::Invalidate() + { + bindGroups.clear(); + } + + void BindGroupCache::Forfeit() + { + const auto currentFrame = Core::ThreadContext::FrameNumber(); + + for (auto i = 0; i < bindGroups.size();) { + const auto& [ptr, lastUsedFrame] = bindGroups[i]; + if (currentFrame - lastUsedFrame > Internal::bindGroupCacheReleaseFrameLatency) { // NOLINT + bindGroups.erase(bindGroups.begin() + i); + } else { + i++; + } } - return views.at(hash).Get(); } -} + + BindGroupCache::BindGroupCache(RHI::Device& inDevice) + : device(inDevice) + { + } +} // namespace Render diff --git a/Engine/Source/Render/Src/RenderGraph.cpp b/Engine/Source/Render/Src/RenderGraph.cpp index 37496724..f1b2f7d2 100644 --- a/Engine/Source/Render/Src/RenderGraph.cpp +++ b/Engine/Source/Render/Src/RenderGraph.cpp @@ -529,7 +529,7 @@ namespace Render { RHI::BindGroup* RGBuilder::GetRHI(RGBindGroupRef inBindGroup) const { AssertWithReason(devirtualizedBindGroups.contains(inBindGroup), "bind group was not devirtualized or has been released"); - return devirtualizedBindGroups.at(inBindGroup).Get(); + return devirtualizedBindGroups.at(inBindGroup); } RGBuilder::AsyncTimelineExecuteContext::AsyncTimelineExecuteContext() = default; @@ -939,7 +939,7 @@ namespace Render { Unimplement(); } } - devirtualizedBindGroups.emplace(std::make_pair(bindGroup, device.CreateBindGroup(createInfo))); + devirtualizedBindGroups.emplace(std::make_pair(bindGroup, BindGroupCache::Get(device).Allocate(createInfo))); } } diff --git a/Engine/Source/Render/Src/Scene.cpp b/Engine/Source/Render/Src/Scene.cpp index 4b1d6842..011ccc80 100644 --- a/Engine/Source/Render/Src/Scene.cpp +++ b/Engine/Source/Render/Src/Scene.cpp @@ -8,16 +8,4 @@ namespace Render { Scene::Scene() = default; Scene::~Scene() = default; - - LightSPH Scene::AddLight() - { - return lights.Emplace(); - } - - void Scene::UpdateLight(const LightSPH& inHandle) {} - - void Scene::RemoveLight(const LightSPH& inHandle) - { - lights.Erase(inHandle); - } } diff --git a/Engine/Source/Render/Src/Shader.cpp b/Engine/Source/Render/Src/Shader.cpp index 94b6f925..0eae4608 100644 --- a/Engine/Source/Render/Src/Shader.cpp +++ b/Engine/Source/Render/Src/Shader.cpp @@ -80,17 +80,17 @@ namespace Render { return rhiHandle != nullptr; } - size_t ShaderInstance::Hash() const + uint64_t ShaderInstance::Hash() const { if (!IsValid()) { return 0; } - const std::vector values = { + const std::vector values = { typeKey, variantKey }; - return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(size_t)); + return Common::HashUtils::CityHash(values.data(), values.size() * sizeof(uint64_t)); } GlobalShaderRegistry& GlobalShaderRegistry::Get() @@ -108,7 +108,7 @@ namespace Render { return shaderTypes; } - void GlobalShaderRegistry::InvalidateAll() const // NOLINT + void GlobalShaderRegistry::Invalidate() const // NOLINT { ShaderArchiveStorage::Get().InvalidateAll(); for (auto* shaderType : shaderTypes) { @@ -118,7 +118,7 @@ namespace Render { void GlobalShaderRegistry::ReloadAll() const { - InvalidateAll(); + Invalidate(); for (auto* shaderType : shaderTypes) { shaderType->Reload(); } diff --git a/Engine/Source/Render/Src/ShaderCompiler.cpp b/Engine/Source/Render/Src/ShaderCompiler.cpp index d8422cac..f4c2154d 100644 --- a/Engine/Source/Render/Src/ShaderCompiler.cpp +++ b/Engine/Source/Render/Src/ShaderCompiler.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #if PLATFORM_WINDOWS #include @@ -117,25 +118,32 @@ namespace Render { return result; } - static std::vector GetInternalPredefinition(const ShaderCompileInput& input, const ShaderCompileOptions& options) + static std::vector GetInternalDefinitions(const ShaderCompileInput& input, const ShaderCompileOptions& options) { static const std::unordered_map stageMacroMap = { - { RHI::ShaderStageBits::sVertex, L"VERTEX_SHADER=1" }, - { RHI::ShaderStageBits::sPixel, L"PIXEL_SHADER=1" }, - { RHI::ShaderStageBits::sCompute, L"COMPUTE_SHADER=1" }, - { RHI::ShaderStageBits::sGeometry, L"GEOMETRY_SHADER=1" }, - { RHI::ShaderStageBits::sHull, L"HULL_SHADER=1" }, - { RHI::ShaderStageBits::sDomain, L"DOMAIN_SHADER=1" } + { RHI::ShaderStageBits::sVertex, L"VERTEX_SHADER" }, + { RHI::ShaderStageBits::sPixel, L"PIXEL_SHADER" }, + { RHI::ShaderStageBits::sCompute, L"COMPUTE_SHADER" }, + { RHI::ShaderStageBits::sGeometry, L"GEOMETRY_SHADER" }, + { RHI::ShaderStageBits::sHull, L"HULL_SHADER" }, + { RHI::ShaderStageBits::sDomain, L"DOMAIN_SHADER" } }; // vulkan std::vector result; result.emplace_back(L"-D"); - result.emplace_back(options.byteCodeType == ShaderByteCodeType::spirv ? L"VULKAN=1" : L"VULKAN=0"); + result.emplace_back(std::format(L"VULKAN={}", options.byteCodeType == ShaderByteCodeType::spirv ? 1 : 0)); // shader stage - result.emplace_back(L"-D"); - result.emplace_back(stageMacroMap.at(input.stage)); + uint8_t trueStageMacro = 0; + for (const auto& [stage, macro] : stageMacroMap) { + if (input.stage == stage) { + trueStageMacro++; + } + result.emplace_back(L"-D"); + result.emplace_back(std::format(L"{}={}", macro, input.stage == stage ? 1 : 0)); + } + Assert(trueStageMacro == 1); return result; } @@ -143,7 +151,7 @@ namespace Render { { std::vector result; - auto preDef = GetInternalPredefinition(input, options); + auto preDef = GetInternalDefinitions(input, options); result.insert(result.end(), preDef.begin(), preDef.end()); for (const auto& definition : input.definitions) { diff --git a/Engine/Source/Render/Src/View.cpp b/Engine/Source/Render/Src/View.cpp index 535f91a8..f533879f 100644 --- a/Engine/Source/Render/Src/View.cpp +++ b/Engine/Source/Render/Src/View.cpp @@ -5,15 +5,14 @@ #include namespace Render { - View::View() = default; - - View::~View() = default; - - void View::Update(const Common::FMat4x4& inViewMatrix, const Common::FMat4x4& inProjectionMatrix, const Common::FRect& inViewport) + ViewRenderData::ViewRenderData() + : viewMatrix(Common::FMat4x4Consts::identity) + , projectionMatrix(Common::FMat4x4Consts::identity) + , viewport() { - viewMatrix = inViewMatrix; - projectionMatrix = inProjectionMatrix; - viewport = inViewport; - // TODO } + + ViewState::ViewState() {} + + View::View() {} } \ No newline at end of file diff --git a/Engine/Source/Render/Test/ResourcePoolTest.cpp b/Engine/Source/Render/Test/ResourcePoolTest.cpp index 6045f3fd..471d6cfb 100644 --- a/Engine/Source/Render/Test/ResourcePoolTest.cpp +++ b/Engine/Source/Render/Test/ResourcePoolTest.cpp @@ -63,9 +63,15 @@ TEST_F(ResourcePoolTest, BasicTest) t3.Reset(); ASSERT_EQ(texturePool.Size(), 3); - texturePool.Tick(); + Core::ThreadContext::IncFrameNumber(); + texturePool.Forfeit(); ASSERT_EQ(texturePool.Size(), 3); - texturePool.Tick(); + Core::ThreadContext::IncFrameNumber(); + texturePool.Forfeit(); + ASSERT_EQ(texturePool.Size(), 3); + + Core::ThreadContext::IncFrameNumber(); + texturePool.Forfeit(); ASSERT_EQ(texturePool.Size(), 1); } diff --git a/Engine/Source/Runtime/Include/Runtime/Asset/Asset.h b/Engine/Source/Runtime/Include/Runtime/Asset/Asset.h index fe4b5fca..d7cf5cfc 100644 --- a/Engine/Source/Runtime/Include/Runtime/Asset/Asset.h +++ b/Engine/Source/Runtime/Include/Runtime/Asset/Asset.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/Engine/Source/Runtime/Include/Runtime/Asset/Level.h b/Engine/Source/Runtime/Include/Runtime/Asset/Level.h index c908f290..8aafe8b5 100644 --- a/Engine/Source/Runtime/Include/Runtime/Asset/Level.h +++ b/Engine/Source/Runtime/Include/Runtime/Asset/Level.h @@ -4,7 +4,7 @@ #pragma once -#include +#include #include #include #include diff --git a/Engine/Source/Runtime/Include/Runtime/Component/Light.h b/Engine/Source/Runtime/Include/Runtime/Component/Light.h index 2bf3a590..efe40ba2 100644 --- a/Engine/Source/Runtime/Include/Runtime/Component/Light.h +++ b/Engine/Source/Runtime/Include/Runtime/Component/Light.h @@ -5,7 +5,7 @@ #pragma once #include -#include +#include #include namespace Runtime { diff --git a/Engine/Source/Runtime/Include/Runtime/Component/Player.h b/Engine/Source/Runtime/Include/Runtime/Component/Player.h new file mode 100644 index 00000000..ae70a1fc --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/Component/Player.h @@ -0,0 +1,32 @@ +// +// Created by johnk on 2025/3/13. +// + +#pragma once + +#include +#include +#include +#include + +namespace Runtime { + struct RUNTIME_API EClass(transient) LocalPlayer { + EClassBody(Player) + + LocalPlayer(); + + Entity activeCamera; + Render::ViewState* viewState; + }; + +#if BUILD_EDITOR + struct RUNTIME_API EClass(transient) EditorVirtualPlayer { + EClassBody(EditorVirtualPlayer) + + EditorVirtualPlayer(); + + Entity activeCamera; + Render::ViewState* viewState; + }; +#endif +} diff --git a/Engine/Source/Runtime/Include/Runtime/Component/Scene.h b/Engine/Source/Runtime/Include/Runtime/Component/Scene.h new file mode 100644 index 00000000..2fa706fc --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/Component/Scene.h @@ -0,0 +1,19 @@ +// +// Created by johnk on 2025/3/13. +// + +#pragma once + +#include +#include +#include + +namespace Runtime { + struct RUNTIME_API EClass(globalComp, transient) SceneHolder final { + EClassBody(SceneHolder) + + explicit SceneHolder(Render::Scene* inScene); + + Render::Scene* scene; + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/Component/Transform.h b/Engine/Source/Runtime/Include/Runtime/Component/Transform.h index 053df219..05b54e94 100644 --- a/Engine/Source/Runtime/Include/Runtime/Component/Transform.h +++ b/Engine/Source/Runtime/Include/Runtime/Component/Transform.h @@ -5,7 +5,7 @@ #pragma once #include -#include +#include #include #include diff --git a/Engine/Source/Runtime/Include/Runtime/Component/View.h b/Engine/Source/Runtime/Include/Runtime/Component/View.h index 9a3f57f9..2dc19aa1 100644 --- a/Engine/Source/Runtime/Include/Runtime/Component/View.h +++ b/Engine/Source/Runtime/Include/Runtime/Component/View.h @@ -4,10 +4,10 @@ #pragma once -#include -#include +#include + +#include #include -#include namespace Runtime { struct RUNTIME_API EClass(transient) Camera final { diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h index 1c23cc4e..5d2aea39 100644 --- a/Engine/Source/Runtime/Include/Runtime/ECS.h +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include namespace Runtime { @@ -25,7 +25,7 @@ namespace Runtime { class ECRegistry; class Client; - class SystemSetupContext; + struct SystemSetupContext; template concept ECRegistryOrConst = std::is_same_v, ECRegistry>; @@ -635,9 +635,16 @@ namespace Runtime { std::vector systemGraph; }; + enum class PlayType : uint8_t { + editor, + game, + max + }; + struct SystemSetupContext { SystemSetupContext(); + PlayType playType; Client* client; }; diff --git a/Engine/Source/Runtime/Include/Runtime/Engine.h b/Engine/Source/Runtime/Include/Runtime/Engine.h index ae235f46..b65f1a92 100644 --- a/Engine/Source/Runtime/Include/Runtime/Engine.h +++ b/Engine/Source/Runtime/Include/Runtime/Engine.h @@ -36,6 +36,8 @@ namespace Runtime { void AttachLogFile() const; void InitRender(const std::string& inRhiTypeStr); + void LoadPlugins() const; + void LoadConfigs() const; std::unordered_set worlds; Render::RenderModule* renderModule; diff --git a/Engine/Source/Runtime/Include/Runtime/GameThread.h b/Engine/Source/Runtime/Include/Runtime/GameThread.h new file mode 100644 index 00000000..df8f89a7 --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/GameThread.h @@ -0,0 +1,89 @@ +// +// Created by Kindem on 2025/3/1. +// + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace Runtime { + class GameThread { + public: + static GameThread& Get(); + + ~GameThread(); + + template auto EmplaceTask(F&& inTask); + + private: + friend class Engine; + + GameThread(); + + void Flush(); + + std::mutex mutex; + std::queue> tasks; + }; + + class GameWorkerThreads { + public: + static GameWorkerThreads& Get(); + + ~GameWorkerThreads(); + + void Start(); + void Stop(); + template auto EmplaceTask(F&& inTask); + template void ExecuteTasks(size_t inTaskNum, F&& inTask); + + private: + GameWorkerThreads(); + + Common::UniquePtr threads; + }; +} + +namespace Runtime { + template + auto GameThread::EmplaceTask(F&& inTask) + { + using RetType = std::invoke_result_t; + auto packagedTask = Common::MakeShared>(inTask); + auto result = packagedTask->get_future(); + { + std::unique_lock lock(mutex); + tasks.emplace([packagedTask]() -> void { (*packagedTask)(); }); + } + return result; + } + + template + auto GameWorkerThreads::EmplaceTask(F&& inTask) + { + using RetType = std::invoke_result_t; + + Assert(threads != nullptr); + return threads->EmplaceTask([inTask]() -> RetType { + Core::ScopedThreadTag tag(Core::ThreadTag::gameWorker); + return inTask(); + }); + } + + template + void GameWorkerThreads::ExecuteTasks(size_t inTaskNum, F&& inTask) + { + Assert(threads != nullptr); + auto reboundTask = std::bind(std::forward(inTask), std::placeholders::_1); + threads->ExecuteTasks(inTaskNum, [reboundTask](size_t inIndex) -> void { + Core::ScopedThreadTag tag(Core::ThreadTag::gameWorker); + reboundTask(inIndex); + }); + } +} // namespace Runtime diff --git a/Engine/Source/Runtime/Include/Runtime/Meta.h b/Engine/Source/Runtime/Include/Runtime/Meta.h new file mode 100644 index 00000000..858f67f2 --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/Meta.h @@ -0,0 +1,15 @@ +// +// Created by johnk on 2025/2/28. +// + +#pragma once + +#include +#include + +namespace Runtime { + struct RUNTIME_API MetaPresets { + static constexpr const auto* globalComp = "globalComp"; + static constexpr const auto* gameReadOnly = "gameReadOnly"; + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/Settings/Game.h b/Engine/Source/Runtime/Include/Runtime/Settings/Game.h new file mode 100644 index 00000000..ea8d89da --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/Settings/Game.h @@ -0,0 +1,26 @@ +// +// Created by johnk on 2025/2/28. +// + +#pragma once + +#include +#include +#include + +namespace Runtime { + class RUNTIME_API EClass(gameReadOnly) GameSettings { + public: + EClassBody(GameSettings) + + GameSettings(); + + EProperty(category=Player) uint8_t maxLocalPlayerNum; + EProperty(category=Player) uint8_t initialLocalPlayerNum; + + EProperty(category=Map) Core::Uri editorStartupLevel; + EProperty(category=Map) Core::Uri gameStartupLevel; + + // TODO more + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/Settings/Registry.h b/Engine/Source/Runtime/Include/Runtime/Settings/Registry.h index 7bfda33a..248b4b40 100644 --- a/Engine/Source/Runtime/Include/Runtime/Settings/Registry.h +++ b/Engine/Source/Runtime/Include/Runtime/Settings/Registry.h @@ -4,7 +4,7 @@ #pragma once -#include +#include #include #include @@ -21,15 +21,15 @@ namespace Runtime { template void RegisterSettings(); template T& GetSettings(); - template void SaveSettings(); template void LoadSettings(); + template void SaveSettings() const; EFunc() void RegisterSettingsDyn(SettingsClass inClass); EFunc() Mirror::Any GetSettingsDyn(SettingsClass inClass); - EFunc() void SaveSettingsDyn(SettingsClass inClass); EFunc() void LoadSettingsDyn(SettingsClass inClass); - EFunc() void SaveAllSettings(); EFunc() void LoadAllSettings(); + EFunc() void SaveSettingsDyn(SettingsClass inClass) const; + EFunc() void SaveAllSettings() const; private: SettingsRegistry(); @@ -54,14 +54,14 @@ namespace Runtime { } template - void SettingsRegistry::SaveSettings() + void SettingsRegistry::LoadSettings() { - SaveSettingsDyn(&Mirror::Class::Get()); + LoadSettingsDyn(&Mirror::Class::Get()); } template - void SettingsRegistry::LoadSettings() + void SettingsRegistry::SaveSettings() const { - LoadSettingsDyn(&Mirror::Class::Get()); + SaveSettingsDyn(&Mirror::Class::Get()); } } diff --git a/Engine/Source/Runtime/Include/Runtime/System/Player.h b/Engine/Source/Runtime/Include/Runtime/System/Player.h new file mode 100644 index 00000000..48db565a --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/System/Player.h @@ -0,0 +1,6 @@ +// +// Created by johnk on 2025/3/13. +// + +#pragma once + diff --git a/Engine/Source/Runtime/Include/Runtime/System/Render.h b/Engine/Source/Runtime/Include/Runtime/System/Render.h new file mode 100644 index 00000000..ee063108 --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/System/Render.h @@ -0,0 +1,26 @@ +// +// Created by johnk on 2025/3/4. +// + +#pragma once + +#include +#include + +namespace Runtime { + class RUNTIME_API EClass() RenderSystem final : public System { + EPolyClassBody(RenderSystem) + + public: + explicit RenderSystem(ECRegistry& inRegistry, const SystemSetupContext& inContext); + ~RenderSystem() override; + + NonCopyable(RenderSystem) + NonMovable(RenderSystem) + + void Tick(float inDeltaTimeSeconds) override; + + private: + // TODO + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/System/Scene.h b/Engine/Source/Runtime/Include/Runtime/System/Scene.h index 3dff2593..cc91f83b 100644 --- a/Engine/Source/Runtime/Include/Runtime/System/Scene.h +++ b/Engine/Source/Runtime/Include/Runtime/System/Scene.h @@ -4,9 +4,12 @@ #pragma once +#include + #include #include #include +#include #include #include #include @@ -25,90 +28,111 @@ namespace Runtime { void Tick(float inDeltaTimeSeconds) override; private: - template using SPMap = std::unordered_map>; - - template static void FillLightSceneProxy(const Render::LightSPH& inHandle, const L& inLight, const WorldTransform* inTransform); - template void EmplaceLightSceneProxy(Entity inEntity); - template void UpdateLightSceneProxy(Entity inEntity); - template void UpdateTransformForSceneProxy(SPMap& inSceneProxyMap, Entity inEntity, bool inWithScale = true); - void RemoveLightSceneProxy(Entity e); + template void QueueCreateSceneProxy(Entity inEntity); + template void QueueUpdateSceneProxyContent(Entity inEntity); + template void QueueUpdateSceneProxyTransform(Entity inEntity); + template void QueueRemoveSceneProxy(Entity inEntity); Render::RenderModule& renderModule; - Common::UniquePtr scene; Observer transformUpdatedObserver; EventsObserver directionalLightsObserver; EventsObserver pointLightsObserver; EventsObserver spotLightsObserver; - SPMap lightSceneProxies; }; } -namespace Runtime { - template - void SceneSystem::FillLightSceneProxy(const Render::LightSPH& inHandle, const L& inLight, const WorldTransform* inTransform) + +namespace Runtime::Internal { + template + static void UpdateSceneProxyContent(SceneProxy& outSceneProxy, const Component& inComponent) { Unimplement(); } + template + static void UpdateSceneProxyWorldTransform(SceneProxy& outSceneProxy, const WorldTransform& inTransform, bool withScale = true) + { + outSceneProxy.localToWorld = withScale ? inTransform.localToWorld.GetTransformMatrix() : inTransform.localToWorld.GetTransformMatrixNoScale(); + } + + template + static std::optional GetOptional(const T* inObj) + { + return inObj == nullptr ? std::optional() : *inObj; + } +} + +namespace Runtime::Internal { template <> - inline void SceneSystem::FillLightSceneProxy(const Render::LightSPH& inHandle, const DirectionalLight& inLight, const WorldTransform* inTransform) + static void UpdateSceneProxyContent(Render::LightSceneProxy& outSceneProxy, const DirectionalLight& inComponent) { - Render::LightSceneProxy& sceneProxy = *inHandle; // NOLINT - sceneProxy.type = Render::LightType::directional; - sceneProxy.localToWorld = inTransform == nullptr ? Common::FMat4x4Consts::identity : inTransform->localToWorld.GetTransformMatrixNoScale(); - sceneProxy.color = inLight.color; - sceneProxy.intensity = inLight.intensity; + outSceneProxy.type = Render::LightType::directional; + outSceneProxy.color = inComponent.color; + outSceneProxy.intensity = inComponent.intensity; } template <> - inline void SceneSystem::FillLightSceneProxy(const Render::LightSPH& inHandle, const PointLight& inLight, const WorldTransform* inTransform) + static void UpdateSceneProxyContent(Render::LightSceneProxy& outSceneProxy, const PointLight& inComponent) { - Render::LightSceneProxy& sceneProxy = *inHandle; // NOLINT - sceneProxy.type = Render::LightType::point; - sceneProxy.localToWorld = inTransform == nullptr ? Common::FMat4x4Consts::identity : inTransform->localToWorld.GetTransformMatrixNoScale(); - sceneProxy.color = inLight.color; - sceneProxy.intensity = inLight.intensity; - sceneProxy.radius = inLight.radius; + outSceneProxy.type = Render::LightType::point; + outSceneProxy.color = inComponent.color; + outSceneProxy.intensity = inComponent.intensity; + outSceneProxy.radius = inComponent.radius; } template <> - inline void SceneSystem::FillLightSceneProxy(const Render::LightSPH& inHandle, const SpotLight& inLight, const WorldTransform* inTransform) + static void UpdateSceneProxyContent(Render::LightSceneProxy& outSceneProxy, const SpotLight& inComponent) + { + outSceneProxy.type = Render::LightType::spot; + outSceneProxy.color = inComponent.color; + outSceneProxy.intensity = inComponent.intensity; + } +} + +namespace Runtime { + template + void SceneSystem::QueueCreateSceneProxy(Entity inEntity) { - Render::LightSceneProxy& sceneProxy = *inHandle; // NOLINT - sceneProxy.type = Render::LightType::spot; - sceneProxy.localToWorld = inTransform == nullptr ? Common::FMat4x4Consts::identity : inTransform->localToWorld.GetTransformMatrixNoScale(); - sceneProxy.color = inLight.color; - sceneProxy.intensity = inLight.intensity; + const auto& sceneHolder = registry.GGet(); + const auto& component = registry.Get(inEntity); + const auto* transform = registry.Find(inEntity); + renderModule.GetRenderThread().EmplaceTask([scene = sceneHolder.scene, inEntity, component, transform = Internal::GetOptional(transform)]() -> void { + SceneProxy sceneProxy; + Internal::UpdateSceneProxyContent(sceneProxy, component); + if (transform.has_value()) { + Internal::UpdateSceneProxyWorldTransform(sceneProxy, transform.value(), false); + } + scene->Add(inEntity, std::move(sceneProxy)); + }); } - template - void SceneSystem::EmplaceLightSceneProxy(Entity inEntity) + template + void SceneSystem::QueueUpdateSceneProxyContent(Entity inEntity) { - lightSceneProxies.emplace(inEntity, scene->AddLight()); - FillLightSceneProxy(lightSceneProxies.at(inEntity), registry.Get(inEntity), registry.Find(inEntity)); + const auto& sceneHolder = registry.GGet(); + const auto& component = registry.Get(inEntity); + renderModule.GetRenderThread().EmplaceTask([scene = sceneHolder.scene, inEntity, component]() -> void { + auto& sceneProxy = scene->Get(inEntity); + Internal::UpdateSceneProxyContent(sceneProxy, component); + }); } - template - void SceneSystem::UpdateLightSceneProxy(Entity inEntity) + template + void SceneSystem::QueueUpdateSceneProxyTransform(Entity inEntity) { - const Render::LightSPH& handle = lightSceneProxies.at(inEntity); - FillLightSceneProxy(handle, registry.Get(inEntity), registry.Find(inEntity)); - scene->UpdateLight(handle); + const auto& sceneHolder = registry.GGet(); + const auto& transform = registry.Get(inEntity); + renderModule.GetRenderThread().EmplaceTask([scene = sceneHolder.scene, inEntity, transform]() -> void { + auto& sceneProxy = scene->Get(inEntity); + Internal::UpdateSceneProxyWorldTransform(sceneProxy, transform, false); + }); } - template - void SceneSystem::UpdateTransformForSceneProxy(SPMap& inSceneProxyMap, Entity inEntity, bool inWithScale) + template + void SceneSystem::QueueRemoveSceneProxy(Entity inEntity) { - const auto iter = inSceneProxyMap.find(inEntity); - if (iter == inSceneProxyMap.end()) { - return; - } - - const Render::LightSPH& handle = iter->second; - if (const WorldTransform* transform = registry.Find(inEntity); - transform == nullptr) { - handle->localToWorld = Common::FMat4x4Consts::identity; - } else { - handle->localToWorld = inWithScale ? transform->localToWorld.GetTransformMatrix() : transform->localToWorld.GetTransformMatrixNoScale();; - } + const auto& sceneHolder = registry.GGet(); + renderModule.GetRenderThread().EmplaceTask([scene = sceneHolder.scene, inEntity]() -> void { + scene->Remove(inEntity); + }); } } diff --git a/Engine/Source/Runtime/Include/Runtime/System/Transform.h b/Engine/Source/Runtime/Include/Runtime/System/Transform.h index 3601fa1e..57fd91cd 100644 --- a/Engine/Source/Runtime/Include/Runtime/System/Transform.h +++ b/Engine/Source/Runtime/Include/Runtime/System/Transform.h @@ -4,7 +4,7 @@ #pragma once -#include +#include #include #include #include diff --git a/Engine/Source/Runtime/Include/Runtime/SystemGraphPresets.h b/Engine/Source/Runtime/Include/Runtime/SystemGraphPresets.h new file mode 100644 index 00000000..3f569691 --- /dev/null +++ b/Engine/Source/Runtime/Include/Runtime/SystemGraphPresets.h @@ -0,0 +1,17 @@ +// +// Created by johnk on 2025/3/13. +// + +#pragma once + +#include +#include + +namespace Runtime { + class RUNTIME_API SystemGraphPresets { + public: + static const SystemGraph& Default3DWorld(); + + SystemGraphPresets() = delete; + }; +} diff --git a/Engine/Source/Runtime/Include/Runtime/World.h b/Engine/Source/Runtime/Include/Runtime/World.h index 5538da96..6162fadf 100644 --- a/Engine/Source/Runtime/Include/Runtime/World.h +++ b/Engine/Source/Runtime/Include/Runtime/World.h @@ -26,7 +26,7 @@ namespace Runtime { NonMovable(World) ~World(); - World(std::string inName, Client* inClient); + World(std::string inName, Client* inClient, PlayType inPlayType); void SetSystemGraph(const SystemGraph& inSystemGraph); PlayStatus PlayStatus() const; bool Stopped() const; diff --git a/Engine/Source/Runtime/Src/Component/Player.cpp b/Engine/Source/Runtime/Src/Component/Player.cpp new file mode 100644 index 00000000..f96b0112 --- /dev/null +++ b/Engine/Source/Runtime/Src/Component/Player.cpp @@ -0,0 +1,19 @@ +// +// Created by johnk on 2025/3/13. +// + +#include + +namespace Runtime { + LocalPlayer::LocalPlayer() + : activeCamera(entityNull) + { + } + +#if BUILD_EDITOR + EditorVirtualPlayer::EditorVirtualPlayer() + : activeCamera(entityNull) + { + } +#endif +} diff --git a/Engine/Source/Runtime/Src/Component/Scene.cpp b/Engine/Source/Runtime/Src/Component/Scene.cpp new file mode 100644 index 00000000..3d31161e --- /dev/null +++ b/Engine/Source/Runtime/Src/Component/Scene.cpp @@ -0,0 +1,12 @@ +// +// Created by johnk on 2025/3/13. +// + +#include + +namespace Runtime { + SceneHolder::SceneHolder(Render::Scene* inScene) + : scene(inScene) + { + } +} diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp index 1cef17cc..bfd90bb1 100644 --- a/Engine/Source/Runtime/Src/ECS.cpp +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -20,7 +20,7 @@ namespace Runtime { namespace Runtime::Internal { static bool IsGlobalCompClass(GCompClass inClass) { - return inClass->HasMeta("global") && inClass->GetMetaBool("global"); + return inClass->GetMetaBoolOr(MetaPresets::globalComp, false); } CompRtti::CompRtti(CompClass inClass) @@ -1288,7 +1288,8 @@ namespace Runtime { } SystemSetupContext::SystemSetupContext() - : client(nullptr) + : playType(PlayType::max) + , client(nullptr) { } diff --git a/Engine/Source/Runtime/Src/Engine.cpp b/Engine/Source/Runtime/Src/Engine.cpp index 4d5daf6f..56015ccf 100644 --- a/Engine/Source/Runtime/Src/Engine.cpp +++ b/Engine/Source/Runtime/Src/Engine.cpp @@ -2,22 +2,25 @@ // Created by johnk on 2024/8/21. // -#include #include #include +#include +#include #include #include -#include #include -#include #include -#include +#include +#include #include +#include namespace Runtime { Engine::Engine(const EngineInitParams& inParams) { Core::ThreadContext::SetTag(Core::ThreadTag::game); + GameWorkerThreads::Get().Start(); + if (!inParams.gameRoot.empty()) { Core::Paths::SetGameRoot(inParams.gameRoot); } @@ -26,15 +29,16 @@ namespace Runtime { AttachLogFile(); } InitRender(inParams.rhiType); - - // TODO load all modules and plugins - SettingsRegistry::Get().LoadAllSettings(); + LoadPlugins(); + LoadConfigs(); } Engine::~Engine() { renderModule->DeInitialize(); ::Core::ModuleManager::Get().Unload("Render"); + + GameWorkerThreads::Get().Stop(); } void Engine::MountWorld(World* inWorld) @@ -59,8 +63,11 @@ namespace Runtime { last2FrameRenderThreadFence.wait(); } + Core::ThreadContext::IncFrameNumber(); + auto& renderThread = renderModule->GetRenderThread(); renderThread.EmplaceTask([]() -> void { + Core::ThreadContext::IncFrameNumber(); Core::Console::Get().PerformRenderThreadSettingsCopy(); }); @@ -71,6 +78,7 @@ namespace Runtime { world->Tick(inDeltaTimeSeconds); } + GameThread::Get().Flush(); last2FrameRenderThreadFence = std::move(lastFrameRenderThreadFence); lastFrameRenderThreadFence = renderThread.EmplaceTask([]() -> void {}); } @@ -96,6 +104,17 @@ namespace Runtime { LogInfo(Render, "RHI type: {}", inRhiTypeStr); } + void Engine::LoadPlugins() const // NOLINT + { + // TODO + } + + void Engine::LoadConfigs() const // NOLINT + { + Core::Console::Get().OverrideSettingsByConfig(); + SettingsRegistry::Get().LoadAllSettings(); + } + Common::UniquePtr EngineHolder::engine = nullptr; MinEngine::MinEngine(const EngineInitParams& inParams) diff --git a/Engine/Source/Runtime/Src/GameThread.cpp b/Engine/Source/Runtime/Src/GameThread.cpp new file mode 100644 index 00000000..c0a38baf --- /dev/null +++ b/Engine/Source/Runtime/Src/GameThread.cpp @@ -0,0 +1,57 @@ +// +// Created by Kindem on 2025/3/1. +// + +#include + +namespace Runtime { + GameThread& GameThread::Get() + { + static GameThread instance; + return instance; + } + + GameThread::GameThread() = default; + + GameThread::~GameThread() + { + Flush(); + } + + void GameThread::Flush() + { + std::queue> tasksToExecute; + { + std::unique_lock lock(mutex); + tasksToExecute.swap(tasks); + } + + while (!tasksToExecute.empty()) { + tasksToExecute.front()(); + tasksToExecute.pop(); + } + } + + GameWorkerThreads& GameWorkerThreads::Get() + { + static GameWorkerThreads instance; + return instance; + } + + + GameWorkerThreads::GameWorkerThreads() = default; + + GameWorkerThreads::~GameWorkerThreads() = default; + + void GameWorkerThreads::Start() + { + Assert(threads == nullptr); + threads = Common::MakeUnique("GameWorkers", 8); + } + + void GameWorkerThreads::Stop() + { + Assert(threads != nullptr); + threads = nullptr; + } +} // namespace Runtime diff --git a/Engine/Source/Runtime/Src/Settings/Game.cpp b/Engine/Source/Runtime/Src/Settings/Game.cpp new file mode 100644 index 00000000..3ab0b242 --- /dev/null +++ b/Engine/Source/Runtime/Src/Settings/Game.cpp @@ -0,0 +1,13 @@ +// +// Created by johnk on 2025/2/28. +// + +#include + +namespace Runtime { + GameSettings::GameSettings() + : maxLocalPlayerNum(1) + , initialLocalPlayerNum(1) + { + } +} diff --git a/Engine/Source/Runtime/Src/Settings/Registry.cpp b/Engine/Source/Runtime/Src/Settings/Registry.cpp index 4e3794c8..e39f07d8 100644 --- a/Engine/Source/Runtime/Src/Settings/Registry.cpp +++ b/Engine/Source/Runtime/Src/Settings/Registry.cpp @@ -2,12 +2,15 @@ // Created by johnk on 2025/2/21. // +#include +#include #include +#include namespace Runtime::Internal { static Common::Path GetConfigPathForSettings(SettingsClass inClass) { - // TODO order: game -> engine + return Core::Paths::GameConfigDir() / std::format("{}.json", inClass->GetName()); } } @@ -36,32 +39,47 @@ namespace Runtime { return settingsMap.at(inClass); } - void SettingsRegistry::SaveSettingsDyn(SettingsClass inClass) - { - // TODO - } - void SettingsRegistry::LoadSettingsDyn(SettingsClass inClass) { - // TODO + const auto configPath = Internal::GetConfigPathForSettings(inClass); + if (!configPath.Exists()) { + return; + } + + const rapidjson::Document document = Common::FileUtils::ReadJsonFile(configPath.String()); + Assert(document.IsObject()); + settingsMap.at(inClass).JsonDeserialize(document); } - void SettingsRegistry::SaveAllSettings() + void SettingsRegistry::LoadAllSettings() { for (const auto* clazz : settingsMap | std::views::keys) { - SaveSettingsDyn(clazz); + LoadSettingsDyn(clazz); } } - void SettingsRegistry::LoadAllSettings() + void SettingsRegistry::SaveSettingsDyn(SettingsClass inClass) const + { +#if !BUILD_EDITOR + Assert(!inClass->GetMetaBoolOr(MetaPresets::gameReadOnly, false)); +#endif + + rapidjson::Document document; + settingsMap.at(inClass).JsonSerialize(document, document.GetAllocator()); + + const auto configPath = Internal::GetConfigPathForSettings(inClass); + Common::FileUtils::WriteJsonFile(configPath.String(), document); + } + + void SettingsRegistry::SaveAllSettings() const { for (const auto* clazz : settingsMap | std::views::keys) { - LoadSettingsDyn(clazz); + SaveSettingsDyn(clazz); } } void SettingsRegistry::RegisterInternalSettings() { - // TODO + RegisterSettings(); } } diff --git a/Engine/Source/Runtime/Src/System/Player.cpp b/Engine/Source/Runtime/Src/System/Player.cpp new file mode 100644 index 00000000..0ac67fd2 --- /dev/null +++ b/Engine/Source/Runtime/Src/System/Player.cpp @@ -0,0 +1,9 @@ +// +// Created by johnk on 2025/3/13. +// + +#include + +namespace Runtime { + +} diff --git a/Engine/Source/Runtime/Src/System/Render.cpp b/Engine/Source/Runtime/Src/System/Render.cpp new file mode 100644 index 00000000..561c76ca --- /dev/null +++ b/Engine/Source/Runtime/Src/System/Render.cpp @@ -0,0 +1,19 @@ +// +// Created by johnk on 2025/3/4. +// + +#include + +namespace Runtime { + RenderSystem::RenderSystem(ECRegistry& inRegistry, const SystemSetupContext& inContext) + : System(inRegistry, inContext) + { + } + + RenderSystem::~RenderSystem() = default; + + void RenderSystem::Tick(float inDeltaTimeSeconds) + { + // TODO + } +} diff --git a/Engine/Source/Runtime/Src/System/Scene.cpp b/Engine/Source/Runtime/Src/System/Scene.cpp index d1f03f2c..d07d29e7 100644 --- a/Engine/Source/Runtime/Src/System/Scene.cpp +++ b/Engine/Source/Runtime/Src/System/Scene.cpp @@ -2,16 +2,16 @@ // Created by johnk on 2025/1/9. // +#include + #include #include #include -#include namespace Runtime { SceneSystem::SceneSystem(ECRegistry& inRegistry, const SystemSetupContext& inContext) : System(inRegistry, inContext) , renderModule(EngineHolder::Get().GetRenderModule()) - , scene(renderModule.NewScene()) , transformUpdatedObserver(inRegistry.Observer()) , directionalLightsObserver(inRegistry.EventsObserver()) , pointLightsObserver(inRegistry.EventsObserver()) @@ -20,32 +20,39 @@ namespace Runtime { transformUpdatedObserver .ObConstructed() .ObUpdated(); + + inRegistry.GEmplace(renderModule.NewScene()); } - SceneSystem::~SceneSystem() = default; + SceneSystem::~SceneSystem() // NOLINT + { + auto& sceneHolder = registry.GGet(); + renderModule.GetRenderThread().EmplaceTask([scene = std::exchange(sceneHolder.scene, nullptr)]() -> void { + delete scene; + }); + } void SceneSystem::Tick(float inDeltaTimeSeconds) { - directionalLightsObserver.Constructed().Each([this](Entity e) -> void { EmplaceLightSceneProxy(e); }); - pointLightsObserver.Constructed().Each([this](Entity e) -> void { EmplaceLightSceneProxy(e); }); - spotLightsObserver.Constructed().Each([this](Entity e) -> void { EmplaceLightSceneProxy(e); }); - directionalLightsObserver.Updated().Each([this](Entity e) -> void { UpdateLightSceneProxy(e); }); - pointLightsObserver.Updated().Each([this](Entity e) -> void { UpdateLightSceneProxy(e); }); - spotLightsObserver.Updated().Each([this](Entity e) -> void { UpdateLightSceneProxy(e); }); - directionalLightsObserver.Removed().Each([this](Entity e) -> void { RemoveLightSceneProxy(e); }); - pointLightsObserver.Removed().Each([this](Entity e) -> void { RemoveLightSceneProxy(e); }); - spotLightsObserver.Removed().Each([this](Entity e) -> void { RemoveLightSceneProxy(e); }); - transformUpdatedObserver.Each([this](Entity e) -> void { UpdateTransformForSceneProxy(lightSceneProxies, e); }); + directionalLightsObserver.Constructed().Each([this](Entity e) -> void { QueueCreateSceneProxy(e); }); + pointLightsObserver.Constructed().Each([this](Entity e) -> void { QueueCreateSceneProxy(e); }); + spotLightsObserver.Constructed().Each([this](Entity e) -> void { QueueCreateSceneProxy(e); }); + directionalLightsObserver.Updated().Each([this](Entity e) -> void { QueueUpdateSceneProxyContent(e); }); + pointLightsObserver.Updated().Each([this](Entity e) -> void { QueueUpdateSceneProxyContent(e); }); + spotLightsObserver.Updated().Each([this](Entity e) -> void { QueueUpdateSceneProxyContent(e); }); + directionalLightsObserver.Removed().Each([this](Entity e) -> void { QueueRemoveSceneProxy(e); }); + pointLightsObserver.Removed().Each([this](Entity e) -> void { QueueRemoveSceneProxy(e); }); + spotLightsObserver.Removed().Each([this](Entity e) -> void { QueueRemoveSceneProxy(e); }); + + transformUpdatedObserver.Each([this](Entity e) -> void { + if (registry.Has(e) || registry.Has(e) || registry.Has(e)) { + QueueUpdateSceneProxyTransform(e); + } + }); transformUpdatedObserver.Clear(); directionalLightsObserver.Clear(); pointLightsObserver.Clear(); spotLightsObserver.Clear(); } - - void SceneSystem::RemoveLightSceneProxy(Entity e) - { - scene->RemoveLight(lightSceneProxies.at(e)); - lightSceneProxies.erase(e); - } } diff --git a/Engine/Source/Runtime/Src/SystemGraphPresets.cpp b/Engine/Source/Runtime/Src/SystemGraphPresets.cpp new file mode 100644 index 00000000..9085d5cb --- /dev/null +++ b/Engine/Source/Runtime/Src/SystemGraphPresets.cpp @@ -0,0 +1,27 @@ +// +// Created by johnk on 2025/3/13. +// + +#include +#include +#include +#include + +namespace Runtime { + const SystemGraph& SystemGraphPresets::Default3DWorld() + { + static SystemGraph graph = []() -> SystemGraph { + SystemGraph systemGraph; + + auto& transformGroup = systemGraph.AddGroup("Transform", SystemExecuteStrategy::sequential); + transformGroup.EmplaceSystem(); + + auto& sceneRenderingGroup = systemGraph.AddGroup("SceneRendering", SystemExecuteStrategy::sequential); + sceneRenderingGroup.EmplaceSystem(); + sceneRenderingGroup.EmplaceSystem(); + + return systemGraph; + }(); + return graph; + } +} diff --git a/Engine/Source/Runtime/Src/World.cpp b/Engine/Source/Runtime/Src/World.cpp index 0060f3d8..cd7cca59 100644 --- a/Engine/Source/Runtime/Src/World.cpp +++ b/Engine/Source/Runtime/Src/World.cpp @@ -8,13 +8,14 @@ #include namespace Runtime { - World::World(std::string inName, Client* inClient) + World::World(std::string inName, Client* inClient, PlayType inPlayType) : name(std::move(inName)) , playStatus(PlayStatus::stopped) , systemSetupContext() { EngineHolder::Get().MountWorld(this); + systemSetupContext.playType = inPlayType; systemSetupContext.client = inClient; } diff --git a/Engine/Source/Runtime/Test/AssetTest.h b/Engine/Source/Runtime/Test/AssetTest.h index 33ed1011..ac7b267c 100644 --- a/Engine/Source/Runtime/Test/AssetTest.h +++ b/Engine/Source/Runtime/Test/AssetTest.h @@ -4,7 +4,7 @@ #pragma once -#include +#include #include using namespace Common; using namespace Runtime; diff --git a/Engine/Source/Runtime/Test/ECSTest.h b/Engine/Source/Runtime/Test/ECSTest.h index f091a78f..efa448e9 100644 --- a/Engine/Source/Runtime/Test/ECSTest.h +++ b/Engine/Source/Runtime/Test/ECSTest.h @@ -4,7 +4,7 @@ #pragma once -#include +#include #include using namespace Runtime; @@ -40,7 +40,7 @@ struct EClass() CompB { EProperty() float value; }; -struct EClass(global) GCompA { +struct EClass(globalComp) GCompA { EClassBody(GCompA) GCompA() @@ -56,7 +56,7 @@ struct EClass(global) GCompA { EProperty() int value; }; -struct EClass(global) GCompB { +struct EClass(globalComp) GCompB { EClassBody(GCompB) GCompB() diff --git a/Engine/Source/Runtime/Test/WorldTest.cpp b/Engine/Source/Runtime/Test/WorldTest.cpp index 5431394f..e5051b1e 100644 --- a/Engine/Source/Runtime/Test/WorldTest.cpp +++ b/Engine/Source/Runtime/Test/WorldTest.cpp @@ -104,7 +104,7 @@ TEST_F(WorldTest, BasicTest) auto& mainGroup = systemGraph.AddGroup("MainGroup", SystemExecuteStrategy::sequential); mainGroup.EmplaceSystemDyn(&BasicTest_MotionSystem::GetStaticClass()); - World world("TestWorld", nullptr); + World world("TestWorld", nullptr, PlayType::game); world.SetSystemGraph(systemGraph); world.Play(); for (auto i = 0; i < 5; i++) { @@ -170,7 +170,7 @@ TEST_F(WorldTest, ConcurrentTest) auto& verifyGroup = systemGraph.AddGroup("VerifyGroup", SystemExecuteStrategy::sequential); verifyGroup.EmplaceSystem(); - World world("TestWorld", nullptr); + World world("TestWorld", nullptr, PlayType::game); world.SetSystemGraph(systemGraph); world.Play(); for (auto i = 0; i < 5; i++) { diff --git a/Engine/Source/Runtime/Test/WorldTest.h b/Engine/Source/Runtime/Test/WorldTest.h index 104c78a9..b3d2bd57 100644 --- a/Engine/Source/Runtime/Test/WorldTest.h +++ b/Engine/Source/Runtime/Test/WorldTest.h @@ -6,7 +6,7 @@ #include -#include +#include #include #include @@ -34,7 +34,7 @@ struct EClass() Velocity { float y; }; -struct EClass(global) GBasicTest_ExpectVerifyResult { +struct EClass(globalComp) GBasicTest_ExpectVerifyResult { EClassBody(GBasicTest_ExpectVerifyResult) std::unordered_map entities; @@ -49,7 +49,7 @@ class EClass() BasicTest_MotionSystem : public Runtime::System { void Tick(float inDeltaTimeSeconds) override; }; -struct EClass(global) GConcurrentTest_Context { +struct EClass(globalComp) GConcurrentTest_Context { EClassBody(GConcurrentTest_Context) uint32_t a; diff --git a/Sample/Base/Application.cpp b/Sample/Base/Application.cpp index e9dbec2b..c228033c 100644 --- a/Sample/Base/Application.cpp +++ b/Sample/Base/Application.cpp @@ -7,6 +7,7 @@ #include #include +#include template <> struct std::hash> { @@ -24,7 +25,9 @@ Application::Application(std::string n) , instance(nullptr) , mousePos(FVec2Consts::zero) , mouseButtonsStatus() - , frameTime(0.0f) + , lastTimeSeconds(TimePoint::Now().ToSeconds()) + , currentTimeSeconds(TimePoint::Now().ToSeconds()) + , deltaTimeSeconds(0.0f) { } @@ -80,12 +83,12 @@ int Application::RunLoop() glfwSetMouseButtonCallback(window, mouseButtonCallback); } - while (!glfwWindowShouldClose(window)) { - const auto currentTime = std::chrono::high_resolution_clock::now(); - frameTime = std::chrono::duration(currentTime - lastTime).count(); - lastTime = currentTime; + while (!static_cast(glfwWindowShouldClose(window))) { + currentTimeSeconds = TimePoint::Now().ToSeconds(); + deltaTimeSeconds = static_cast(currentTimeSeconds - lastTimeSeconds); + lastTimeSeconds = currentTimeSeconds; if (camera != nullptr) { - camera->Update(GetFrameTime()); + camera->Update(GetDeltaTimeSeconds()); } OnDrawFrame(); glfwPollEvents(); @@ -170,12 +173,24 @@ void Application::OnCursorActionReceived(float x, float y) void Application::OnMouseButtonActionReceived(int button, int action) { static std::unordered_map, std::function> actionMap = { - { { GLFW_PRESS, GLFW_MOUSE_BUTTON_LEFT }, [](Application& application) -> void { application.mouseButtonsStatus[static_cast(MouseButton::left)] = true; } }, - { { GLFW_PRESS, GLFW_MOUSE_BUTTON_RIGHT }, [](Application& application) -> void { application.mouseButtonsStatus[static_cast(MouseButton::right)] = true; } }, - { { GLFW_PRESS, GLFW_MOUSE_BUTTON_MIDDLE }, [](Application& application) -> void { application.mouseButtonsStatus[static_cast(MouseButton::middle)] = true; } }, - { { GLFW_RELEASE, GLFW_MOUSE_BUTTON_LEFT }, [](Application& application) -> void { application.mouseButtonsStatus[static_cast(MouseButton::left)] = false; } }, - { { GLFW_RELEASE, GLFW_MOUSE_BUTTON_RIGHT }, [](Application& application) -> void { application.mouseButtonsStatus[static_cast(MouseButton::right)] = false; } }, - { { GLFW_RELEASE, GLFW_MOUSE_BUTTON_MIDDLE }, [](Application& application) -> void { application.mouseButtonsStatus[static_cast(MouseButton::middle)] = false; } }, + {{GLFW_PRESS, GLFW_MOUSE_BUTTON_LEFT}, [](Application& application) -> void { + application.mouseButtonsStatus[static_cast(MouseButton::left)] = true; + }}, + {{GLFW_PRESS, GLFW_MOUSE_BUTTON_RIGHT}, [](Application& application) -> void { + application.mouseButtonsStatus[static_cast(MouseButton::right)] = true; + }}, + {{GLFW_PRESS, GLFW_MOUSE_BUTTON_MIDDLE}, [](Application& application) -> void { + application.mouseButtonsStatus[static_cast(MouseButton::middle)] = true; + }}, + {{GLFW_RELEASE, GLFW_MOUSE_BUTTON_LEFT}, [](Application& application) -> void { + application.mouseButtonsStatus[static_cast(MouseButton::left)] = false; + }}, + {{GLFW_RELEASE, GLFW_MOUSE_BUTTON_RIGHT}, [](Application& application) -> void { + application.mouseButtonsStatus[static_cast(MouseButton::right)] = false; + }}, + {{GLFW_RELEASE, GLFW_MOUSE_BUTTON_MIDDLE}, [](Application& application) -> void { + application.mouseButtonsStatus[static_cast(MouseButton::middle)] = false; + }}, }; const auto iter = actionMap.find(std::make_pair(action, button)); @@ -185,9 +200,14 @@ void Application::OnMouseButtonActionReceived(int button, int action) iter->second(*this); } -float Application::GetFrameTime() const +double Application::GetCurrentTimeSeconds() const { - return frameTime; + return currentTimeSeconds; +} + +float Application::GetDeltaTimeSeconds() const +{ + return deltaTimeSeconds; } void* Application::GetPlatformWindow() const diff --git a/Sample/Base/Application.h b/Sample/Base/Application.h index fe72e97f..28035ed3 100644 --- a/Sample/Base/Application.h +++ b/Sample/Base/Application.h @@ -52,7 +52,8 @@ class Application { void SetCamera(Camera* inCamera); const std::string& GetApplicationName() const; - float GetFrameTime() const; + double GetCurrentTimeSeconds() const; + float GetDeltaTimeSeconds() const; void* GetPlatformWindow() const; uint32_t GetWindowWidth() const; uint32_t GetWindowHeight() const; @@ -70,6 +71,7 @@ class Application { UniquePtr camera; FVec2 mousePos; std::array(MouseButton::max)> mouseButtonsStatus; - std::chrono::time_point lastTime; - float frameTime; + double lastTimeSeconds; + double currentTimeSeconds; + float deltaTimeSeconds; }; diff --git a/Sample/RHI-SSAO/SSAOApplication.cpp b/Sample/RHI-SSAO/SSAOApplication.cpp index 32241a98..ca8cdc2b 100644 --- a/Sample/RHI-SSAO/SSAOApplication.cpp +++ b/Sample/RHI-SSAO/SSAOApplication.cpp @@ -1003,7 +1003,7 @@ class SSAOApplication final : public Application { 64.0f }); - camera->SetMoveSpeed(0.005f); + camera->SetMoveSpeed(5.f); camera->SetRotateSpeed(0.1f); SetCamera(camera); } diff --git a/Sample/Rendering-Triangle/Triangle.cpp b/Sample/Rendering-Triangle/Triangle.cpp index 8639777f..49bc77b8 100644 --- a/Sample/Rendering-Triangle/Triangle.cpp +++ b/Sample/Rendering-Triangle/Triangle.cpp @@ -14,7 +14,6 @@ using namespace RHI; struct Vertex { FVec3 position; - FVec3 color; }; class TriangleVS : public GlobalShader { @@ -44,6 +43,10 @@ class TrianglePS : public GlobalShader { RegisterGlobalShader(TriangleVS); RegisterGlobalShader(TrianglePS); +struct PsUniform { + FVec3 pixelColor; +}; + class TriangleApplication final : public Application { public: explicit TriangleApplication(const std::string& inName); @@ -68,7 +71,7 @@ class TriangleApplication final : public Application { UniquePtr device; UniquePtr surface; UniquePtr swapChain; - std::array swapChainTextures {}; + std::array swapChainTextures; UniquePtr triangleVertexBuffer; UniquePtr imageReadySemaphore; UniquePtr renderFinishedSemaphore; @@ -78,6 +81,7 @@ class TriangleApplication final : public Application { TriangleApplication::TriangleApplication(const std::string& inName) : Application(inName) , swapChainFormat(PixelFormat::max) + , swapChainTextures() { } @@ -106,8 +110,7 @@ void TriangleApplication::OnDrawFrame() RVertexState() .AddVertexBufferLayout( RVertexBufferLayout(VertexStepMode::perVertex, sizeof(Vertex)) - .AddAttribute(RVertexAttribute(RVertexBinding("POSITION", 0), VertexFormat::float32X3, offsetof(Vertex, position))) - .AddAttribute(RVertexAttribute(RVertexBinding("COLOR", 0), VertexFormat::float32X3, offsetof(Vertex, color))))) + .AddAttribute(RVertexAttribute(RVertexBinding("POSITION", 0), VertexFormat::float32X3, offsetof(Vertex, position))))) .SetFragmentState( RFragmentState() .AddColorTarget(ColorTargetState(swapChainFormat, ColorWriteBits::all, false)))); @@ -117,18 +120,35 @@ void TriangleApplication::OnDrawFrame() auto* backTextureView = builder.CreateTextureView(backTexture, RGTextureViewDesc(TextureViewType::colorAttachment, TextureViewDimension::tv2D)); auto* vertexBuffer = builder.ImportBuffer(triangleVertexBuffer.Get(), BufferState::shaderReadOnly); auto* vertexBufferView = builder.CreateBufferView(vertexBuffer, RGBufferViewDesc(BufferViewType::vertex, vertexBuffer->GetDesc().size, 0, VertexBufferViewInfo(sizeof(Vertex)))); + auto* psUniformBuffer = builder.CreateBuffer(RGBufferDesc(sizeof(PsUniform), BufferUsageBits::uniform | BufferUsageBits::mapWrite, BufferState::staging, "psUniform")); + auto* psUniformBufferView = builder.CreateBufferView(psUniformBuffer, RGBufferViewDesc(BufferViewType::uniformBinding, sizeof(PsUniform))); + + auto* bindGroup = builder.AllocateBindGroup( + RGBindGroupDesc::Create(pso->GetPipelineLayout()->GetBindGroupLayout(0)) + .UniformBuffer("psUniform", psUniformBufferView)); + + PsUniform psUniform {}; + psUniform.pixelColor = FVec3( + (std::sin(GetCurrentTimeSeconds()) + 1) / 2, + (std::cos(GetCurrentTimeSeconds()) + 1) / 2, + std::abs(std::sin(GetCurrentTimeSeconds()))); + + builder.QueueBufferUpload( + psUniformBuffer, + RGBufferUploadInfo(&psUniform, sizeof(PsUniform))); builder.AddRasterPass( "BasePass", RGRasterPassDesc() .AddColorAttachment(RGColorAttachment(backTextureView, LoadOp::clear, StoreOp::store)), - {}, - [pso, vertexBufferView, viewportWidth = GetWindowWidth(), viewportHeight = GetWindowHeight()](const RGBuilder& rg, RasterPassCommandRecorder& recorder) -> void { + { bindGroup }, + [pso, vertexBufferView, bindGroup, viewportWidth = GetWindowWidth(), viewportHeight = GetWindowHeight()](const RGBuilder& rg, RasterPassCommandRecorder& recorder) -> void { recorder.SetPipeline(pso->GetRHI()); recorder.SetScissor(0, 0, viewportWidth, viewportHeight); recorder.SetViewport(0, 0, static_cast(viewportWidth), static_cast(viewportHeight), 0, 1); recorder.SetVertexBuffer(0, rg.GetRHI(vertexBufferView)); recorder.SetPrimitiveTopology(PrimitiveTopology::triangleList); + recorder.SetBindGroup(0, rg.GetRHI(bindGroup)); recorder.Draw(3, 1, 0, 0); }, {}, @@ -144,8 +164,11 @@ void TriangleApplication::OnDrawFrame() swapChain->Present(renderFinishedSemaphore.Get()); frameFence->Wait(); - BufferPool::Get(*device).Tick(); - TexturePool::Get(*device).Tick(); + Core::ThreadContext::IncFrameNumber(); + BufferPool::Get(*device).Forfeit(); + TexturePool::Get(*device).Forfeit(); + ResourceViewCache::Get(*device).Forfeit(); + BindGroupCache::Get(*device).Forfeit(); } void TriangleApplication::OnDestroy() @@ -154,9 +177,11 @@ void TriangleApplication::OnDestroy() device->GetQueue(QueueType::graphics, 0)->Flush(fence.Get()); fence->Wait(); - ResourceViewCache::Get(*device).Invalidate(); + BindGroupCache::Get(*device).Invalidate(); PipelineCache::Get(*device).Invalidate(); - GlobalShaderRegistry::Get().InvalidateAll(); + BufferPool::Get(*device).Invalidate(); + TexturePool::Get(*device).Invalidate(); + GlobalShaderRegistry::Get().Invalidate(); RenderWorkerThreads::Get().Stop(); } @@ -218,9 +243,9 @@ void TriangleApplication::CreateSwapChain() void TriangleApplication::CreateTriangleVertexBuffer() { const std::vector vertices = { - { { -.5f, -.5f, 0.f }, { 1.f, 0.f, 0.f } }, - { { .5f, -.5f, 0.f }, { 0.f, 1.f, 0.f } }, - { { 0.f, .5f, 0.f }, { 0.f, 0.f, 1.f } }, + { { -.5f, -.5f, 0.f } }, + { { .5f, -.5f, 0.f } }, + { { 0.f, .5f, 0.f } }, }; const BufferCreateInfo bufferCreateInfo = BufferCreateInfo() diff --git a/Sample/Rendering-Triangle/Triangle.esl b/Sample/Rendering-Triangle/Triangle.esl index e3832dbd..88670e7d 100644 --- a/Sample/Rendering-Triangle/Triangle.esl +++ b/Sample/Rendering-Triangle/Triangle.esl @@ -1,24 +1,24 @@ #include -struct FragmentInput { - float4 position : SV_POSITION; - float4 color : COLOR; -}; - -FragmentInput VSMain( - VkLocation(0) float4 position : POSITION, - VkLocation(1) float4 color : COLOR) +#if VERTEX_SHADER +float4 VSMain( + VkLocation(0) float4 position : POSITION) : SV_POSITION { - FragmentInput fragmentInput; - fragmentInput.position = position; + float4 pos = position; #if VULKAN - fragmentInput.position.y = - fragmentInput.position.y; + pos.y = - pos.y; #endif - fragmentInput.color = color; - return fragmentInput; + return pos; } +#endif -float4 PSMain(FragmentInput input) : SV_TARGET +#if PIXEL_SHADER +cbuffer psUniform { + float3 pixelColor; +}; + +float4 PSMain() : SV_TARGET { - return input.color; -} \ No newline at end of file + return float4(pixelColor, 1.0f); +} +#endif