diff --git a/CMake/ThirdParty.cmake b/CMake/ThirdParty.cmake index 1e8a7cb81..dd14c9483 100644 --- a/CMake/ThirdParty.cmake +++ b/CMake/ThirdParty.cmake @@ -503,3 +503,33 @@ function(Find3rdPackage) ) endif() endfunction() + +function(Setup3rdPackage) + cmake_parse_arguments(PARAMS "" "NAME;PLATFORM;VERSION" "HASH" ${ARGN}) + + set(NAME "${PARAMS_NAME}") + if (DEFINED PARAMS_PLATFORM) + if ((NOT (${PARAMS_PLATFORM} STREQUAL "All")) AND (NOT (${PARAMS_PLATFORM} STREQUAL ${CMAKE_SYSTEM_NAME}))) + return() + endif() + set(FULL_NAME "${PARAMS_NAME}-${PARAMS_PLATFORM}-${PARAMS_VERSION}") + else() + set(FULL_NAME "${PARAMS_NAME}-${CMAKE_SYSTEM_NAME}-${PARAMS_VERSION}") + endif() + set(URL "${3RD_REPO}/${FULL_NAME}.7z") + set(ZIP "${3RD_ZIP_DIR}/${FULL_NAME}.7z") + set(SOURCE_DIR "${3RD_SOURCE_DIR}/${FULL_NAME}") + + Get3rdPlatformValue( + OUTPUT HASH_VALUE + INPUT ${PARAMS_HASH} + ) + DownloadAndExtract3rdPackage( + URL ${URL} + SAVE_AS ${ZIP} + EXTRACT_TO ${SOURCE_DIR} + HASH ${HASH_VALUE} + ) + + set(${PARAMS_NAME}_SOURCE_DIR ${SOURCE_DIR}) +endfunction() diff --git a/Editor/QML/launcher.qml b/Editor/QML/launcher.qml new file mode 100644 index 000000000..f8c63e1ff --- /dev/null +++ b/Editor/QML/launcher.qml @@ -0,0 +1,5 @@ +import QtQuick + +Rectangle { + color: 'red' +} diff --git a/Editor/Resource/logo.png b/Editor/Resource/logo.png deleted file mode 100644 index daffbafaf..000000000 Binary files a/Editor/Resource/logo.png and /dev/null differ diff --git a/Editor/Source/CMakeLists.txt b/Editor/Source/CMakeLists.txt index 67bc6f3ab..3ad567ab3 100644 --- a/Editor/Source/CMakeLists.txt +++ b/Editor/Source/CMakeLists.txt @@ -1,21 +1,29 @@ -file(GLOB_RECURSE RESOURCES ../Resource/*) -foreach(R ${RESOURCES}) - string(REGEX REPLACE ".*Resource/" "" FILENAME ${R}) - list(APPEND FINAL_RESOURCES ${R}->../Resource/${FILENAME}) -endforeach() +set(CMAKE_PREFIX_PATH ${QT_LIB_PREFIX}) +find_package( + Qt6 ${QT_VERSION} + COMPONENTS Core Gui Widgets Quick + REQUIRED +) + +qt_standard_project_setup(REQUIRES ${QT_VERSION}) file(GLOB_RECURSE SOURCES Src/*.cpp) -AddExecutable( - NAME Editor - SRC ${SOURCES} - INC Include - LIB Qt Core RHI Runtime - RES ${FINAL_RESOURCES} -) +qt_add_executable(Editor ${SOURCES}) +target_include_directories(Editor PRIVATE Include) +target_link_libraries(Editor PRIVATE Core RHI Runtime Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Quick) + +file(GLOB_RECURSE QML_SOURCES ../QML/*.qml) +file(GLOB_RECURSE RESOURCES ../Resource/*) + +list(APPEND RESOURCES_PENDING_SET_ALIAS ${QML_SOURCES} ${RESOURCES}) +foreach (RESOURCE ${RESOURCES_PENDING_SET_ALIAS}) + get_filename_component(FILENAME ${RESOURCE} NAME) + set_source_files_properties(${RESOURCE} PROPERTIES QT_RESOURCE_ALIAS ${FILENAME}) +endforeach () -set_target_properties( - Editor PROPERTIES - AUTOMOC ON - AUTORCC ON - AUTOUIC ON +qt_add_qml_module( + Editor + URI editor + QML_FILES ${QML_SOURCES} + RESOURCES ${RESOURCES} ) diff --git a/Editor/Source/Include/Editor/EditorModule.h b/Editor/Source/Include/Editor/EditorModule.h index a01d8d68c..3caee2ee2 100644 --- a/Editor/Source/Include/Editor/EditorModule.h +++ b/Editor/Source/Include/Editor/EditorModule.h @@ -7,13 +7,10 @@ #include namespace Editor { - class EditorModule final : public Runtime::IGameModule { + class EditorModule final : public Runtime::IEngineModule { public: void OnUnload() override; ::Core::ModuleType Type() const override; Runtime::Engine* CreateEngine(const Runtime::EngineInitParams&) override; - - private: - Common::UniqueRef engine; }; } diff --git a/Editor/Source/Include/Editor/QmlHotReload.h b/Editor/Source/Include/Editor/QmlHotReload.h new file mode 100644 index 000000000..57b52e435 --- /dev/null +++ b/Editor/Source/Include/Editor/QmlHotReload.h @@ -0,0 +1,28 @@ +// +// Created by Kindem on 2024/12/31. +// + +#pragma once + +#include + +#include + +namespace Editor { + class QmlHotReloadEngine { + public: + static QmlHotReloadEngine& Get(); + + ~QmlHotReloadEngine(); + + void Start(); + void Stop(); + void Register(QQuickView* inView); + void Unregister(QQuickView* inView); + + private: + QmlHotReloadEngine(); + + std::unordered_set liveQuickViews; + }; +} diff --git a/Editor/Source/Include/Editor/Resource.h b/Editor/Source/Include/Editor/Resource.h deleted file mode 100644 index 151ef543d..000000000 --- a/Editor/Source/Include/Editor/Resource.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// Created by johnk on 2024/8/23. -// - -#pragma once - -#include - -#include - -namespace Editor { - class Resource { - public: - explicit Resource(std::string inFile); - - std::filesystem::path Path() const; - std::string String() const; - operator std::filesystem::path() const; // NOLINT - operator std::string() const; // NOLINT - operator QString() const; // NOLINT - - private: - std::string file; - }; - - class StaticResources { - public: - static Resource picLogo; - }; -} diff --git a/Editor/Source/Include/Editor/Theme.h b/Editor/Source/Include/Editor/Theme.h deleted file mode 100644 index ebdbc63c6..000000000 --- a/Editor/Source/Include/Editor/Theme.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// Created by johnk on 2024/8/23. -// - -#pragma once - -#include - -namespace Editor { - class Theme { - public: - Theme(); - - Theme& SetColorPrimary(const QColor& color); - Theme& SetColorSecondary(const QColor& color); - Theme& SetColorBackground(const QColor& color); - QColor GetColorPrimary() const; - QColor GetColorSecondary() const; - QColor GetColorBackground() const; - - private: - QColor colorPrimary; - QColor colorSecondary; - QColor colorBackground; - }; - - extern Theme defaultTheme; - - class ThemeSwitcher { - public: - static void Set(const Theme& inTheme); - static const Theme& Current(); - - private: - static Theme current; - }; -} diff --git a/Editor/Source/Include/Editor/Widget/Launcher.h b/Editor/Source/Include/Editor/Widget/Launcher.h index 0c5f27c5b..fc8335d05 100644 --- a/Editor/Source/Include/Editor/Widget/Launcher.h +++ b/Editor/Source/Include/Editor/Widget/Launcher.h @@ -4,20 +4,13 @@ #pragma once -#include -#include +#include namespace Editor { - class Launcher final : public QWidget { + class Launcher final : public QmlWidget { Q_OBJECT public: Launcher(); - - void SetWindowProperties(); - void CreateMainCol(); - void CreateLogoRow() const; - - QVBoxLayout* mainCol; }; } diff --git a/Editor/Source/Include/Editor/Widget/QmlWidget.h b/Editor/Source/Include/Editor/Widget/QmlWidget.h new file mode 100644 index 000000000..9fed2f42b --- /dev/null +++ b/Editor/Source/Include/Editor/Widget/QmlWidget.h @@ -0,0 +1,24 @@ +// +// Created by Kindem on 2024/12/31. +// + +#pragma once + +#include +#include + +namespace Editor { + class QmlWidget : public QWidget { + Q_OBJECT + + public: + explicit QmlWidget(const std::string& qmlFileName, QWidget* parent = nullptr); + + QQuickView* GetQuickView(); + const QUrl& GetQmlUrl() const; + + private: + QUrl url; + QQuickView* quickView; + }; +} diff --git a/Editor/Source/Src/Core.cpp b/Editor/Source/Src/Core.cpp index d958b563a..e0760c60e 100644 --- a/Editor/Source/Src/Core.cpp +++ b/Editor/Source/Src/Core.cpp @@ -35,6 +35,8 @@ namespace Editor { void Core::Cleanup() // NOLINT { + Runtime::EngineHolder::Unload(); + engine = nullptr; ::Core::ModuleManager::Get().Unload("Runtime"); } diff --git a/Editor/Source/Src/EditorModule.cpp b/Editor/Source/Src/EditorModule.cpp index dd0737c69..bd5c810e6 100644 --- a/Editor/Source/Src/EditorModule.cpp +++ b/Editor/Source/Src/EditorModule.cpp @@ -9,7 +9,6 @@ namespace Editor { void EditorModule::OnUnload() { Runtime::EngineHolder::Unload(); - engine.Reset(); } ::Core::ModuleType EditorModule::Type() const @@ -19,9 +18,7 @@ namespace Editor { Runtime::Engine* EditorModule::CreateEngine(const Runtime::EngineInitParams& inParams) { - Assert(engine == nullptr); - engine = new EditorEngine(inParams); - return engine.Get(); + return new EditorEngine(inParams); } } diff --git a/Editor/Source/Src/Main.cpp b/Editor/Source/Src/Main.cpp index b6415ec09..038ea78f9 100644 --- a/Editor/Source/Src/Main.cpp +++ b/Editor/Source/Src/Main.cpp @@ -4,6 +4,7 @@ #include #include +#include #include int main(int argc, char* argv[]) @@ -19,7 +20,11 @@ int main(int argc, char* argv[]) // TODO editor main } mainWindow->show(); + + auto& qmlHotReloadEngine = Editor::QmlHotReloadEngine::Get(); + qmlHotReloadEngine.Start(); const int execRes = QApplication::exec(); + qmlHotReloadEngine.Stop(); mainWindow = nullptr; Editor::Core::Get().Cleanup(); diff --git a/Editor/Source/Src/QmlHotReload.cpp b/Editor/Source/Src/QmlHotReload.cpp new file mode 100644 index 000000000..170c37cdb --- /dev/null +++ b/Editor/Source/Src/QmlHotReload.cpp @@ -0,0 +1,37 @@ +// +// Created by Kindem on 2024/12/31. +// + +#include + +namespace Editor { + QmlHotReloadEngine& QmlHotReloadEngine::Get() + { + static QmlHotReloadEngine engine; + return engine; + } + + QmlHotReloadEngine::QmlHotReloadEngine() = default; + + QmlHotReloadEngine::~QmlHotReloadEngine() = default; + + void QmlHotReloadEngine::Start() + { + // TODO + } + + void QmlHotReloadEngine::Stop() + { + // TODO + } + + void QmlHotReloadEngine::Register(QQuickView* inView) + { + liveQuickViews.emplace(inView); + } + + void QmlHotReloadEngine::Unregister(QQuickView* inView) + { + liveQuickViews.erase(inView); + } +} // namespace Editor diff --git a/Editor/Source/Src/Resource.cpp b/Editor/Source/Src/Resource.cpp deleted file mode 100644 index 2f38d5375..000000000 --- a/Editor/Source/Src/Resource.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// Created by johnk on 2024/8/23. -// - -#include -#include - -namespace Editor { - Resource::Resource(std::string inFile) - : file(std::move(inFile)) - { - } - - std::filesystem::path Resource::Path() const - { - return ::Core::Paths::EngineRes() / file; - } - - std::string Resource::String() const - { - return Path().string(); - } - - Resource::operator std::filesystem::path() const - { - return Path(); - } - - Resource::operator std::string() const - { - return String(); - } - - Resource::operator QString() const - { - return QString::fromStdString(String()); - } - - Resource StaticResources::picLogo = Resource("logo.png"); -} diff --git a/Editor/Source/Src/Theme.cpp b/Editor/Source/Src/Theme.cpp deleted file mode 100644 index 68c5d3362..000000000 --- a/Editor/Source/Src/Theme.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// -// Created by johnk on 2024/8/23. -// - -#include - -namespace Editor { - Theme::Theme() - : colorPrimary() - , colorSecondary() - , colorBackground(0x24, 0x29, 0x2f) - { - } - - Theme& Theme::SetColorPrimary(const QColor& color) - { - colorPrimary = color; - return *this; - } - - Theme& Theme::SetColorSecondary(const QColor& color) - { - colorSecondary = color; - return *this; - } - - Theme& Theme::SetColorBackground(const QColor& color) - { - colorBackground = color; - return *this; - } - - QColor Theme::GetColorPrimary() const - { - return colorPrimary; - } - - QColor Theme::GetColorSecondary() const - { - return colorSecondary; - } - - QColor Theme::GetColorBackground() const - { - return colorBackground; - } - - Theme defaultTheme = Theme(); // NOLINT - - void ThemeSwitcher::Set(const Theme& inTheme) - { - current = inTheme; - } - - const Theme& ThemeSwitcher::Current() - { - return current; - } - - Theme ThemeSwitcher::current = defaultTheme; -} diff --git a/Editor/Source/Src/Widget/Launcher.cpp b/Editor/Source/Src/Widget/Launcher.cpp index 216a44a51..8dab65c08 100644 --- a/Editor/Source/Src/Widget/Launcher.cpp +++ b/Editor/Source/Src/Widget/Launcher.cpp @@ -2,48 +2,12 @@ // Created by johnk on 2024/6/23. // -#include -#include - #include #include // NOLINT -#include -#include namespace Editor { Launcher::Launcher() + : QmlWidget("launcher.qml") { - SetWindowProperties(); - CreateMainCol(); - CreateLogoRow(); - } - - void Launcher::SetWindowProperties() - { - setFixedSize(QSize(800, 600)); - setWindowTitle(tr("Launcher")); - setWindowIcon(QIcon(StaticResources::picLogo)); - - QPalette pal(palette()); - pal.setColor(backgroundRole(), ThemeSwitcher::Current().GetColorBackground()); - setPalette(pal); - } - - void Launcher::CreateMainCol() - { - mainCol = new QVBoxLayout(); - setLayout(mainCol); - } - - void Launcher::CreateLogoRow() const - { - auto* logoRow = new QHBoxLayout(); - logoRow->setContentsMargins(QMargins(0, 50, 0, 0)); - mainCol->addLayout(logoRow); - - auto* logoLabel = new QLabel(); - logoLabel->setPixmap(QPixmap(StaticResources::picLogo).scaled(250, 250, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - logoLabel->setAlignment(Qt::AlignHCenter); - mainCol->addWidget(logoLabel); } } diff --git a/Editor/Source/Src/Widget/QmlWidget.cpp b/Editor/Source/Src/Widget/QmlWidget.cpp new file mode 100644 index 000000000..9df364566 --- /dev/null +++ b/Editor/Source/Src/Widget/QmlWidget.cpp @@ -0,0 +1,42 @@ +// +// Created by Kindem on 2024/12/31. +// + +#include + +#include +#include // NOLINT + +namespace Editor { + QmlWidget::QmlWidget(const std::string& qmlFileName, QWidget* parent) + : QWidget(parent) + , url(QUrl(QString(std::format("qrc:/qt/qml/editor/{}", qmlFileName).c_str()))) + , quickView(new QQuickView) + { + quickView->setResizeMode(QQuickView::SizeRootObjectToView); + quickView->setSource(url); + quickView->show(); + + QWidget* quickViewContainer = createWindowContainer(quickView); + quickViewContainer->setMinimumSize(quickView->size()); + quickViewContainer->setFocusPolicy(Qt::TabFocus); + + QVBoxLayout* layout = new QVBoxLayout(); // NOLINT + setLayout(layout); + + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(quickViewContainer); + + // TODO support hot reload + } + + QQuickView* QmlWidget::GetQuickView() // NOLINT + { + return quickView; + } + + const QUrl& QmlWidget::GetQmlUrl() const + { + return url; + } +} // namespace Editor diff --git a/Engine/Source/Common/Include/Common/Event.h b/Engine/Source/Common/Include/Common/Delegate.h similarity index 69% rename from Engine/Source/Common/Include/Common/Event.h rename to Engine/Source/Common/Include/Common/Delegate.h index cf8db02d0..ed48b6cdb 100644 --- a/Engine/Source/Common/Include/Common/Event.h +++ b/Engine/Source/Common/Include/Common/Delegate.h @@ -29,41 +29,41 @@ namespace Common::Internal { } namespace Common { - using ReceiverHandle = size_t; + using CallbackHandle = size_t; template - class Event { + class Delegate { public: - Event(); + Delegate(); - template ReceiverHandle BindStatic(); - template ReceiverHandle BindMember(C& inObj); - template ReceiverHandle BindLambda(F&& inLambda); + template CallbackHandle BindStatic(); + template CallbackHandle BindMember(C& inObj); + template CallbackHandle BindLambda(F&& inLambda); template void Broadcast(Args&&... inArgs) const; - void Unbind(ReceiverHandle inHandle); - size_t ReceiversCount() const; + void Unbind(CallbackHandle inHandle); + size_t Count() const; void Reset(); private: - template void BindStaticInternal(ReceiverHandle inHandle, std::index_sequence); - template void BindMemberInternal(ReceiverHandle inHandle, C& inObj, std::index_sequence); - template void BindLambdaInternal(ReceiverHandle inHandle, F&& inLambda, std::index_sequence); + template void BindStaticInternal(CallbackHandle inHandle, std::index_sequence); + template void BindMemberInternal(CallbackHandle inHandle, C& inObj, std::index_sequence); + template void BindLambdaInternal(CallbackHandle inHandle, F&& inLambda, std::index_sequence); - ReceiverHandle counter; - std::vector>> receivers; + CallbackHandle counter; + std::vector>> receivers; }; } namespace Common { template - Event::Event() + Delegate::Delegate() : counter(0) { } template template - ReceiverHandle Event::BindStatic() + CallbackHandle Delegate::BindStatic() { const auto handle = counter++; BindStaticInternal(handle, std::make_index_sequence()); @@ -72,7 +72,7 @@ namespace Common { template template - ReceiverHandle Event::BindMember(C& inObj) + CallbackHandle Delegate::BindMember(C& inObj) { const auto handle = counter++; BindMemberInternal(handle, inObj, std::make_index_sequence()); @@ -81,7 +81,7 @@ namespace Common { template template - ReceiverHandle Event::BindLambda(F&& inLambda) + CallbackHandle Delegate::BindLambda(F&& inLambda) { const auto handle = counter++; BindLambdaInternal(handle, std::forward(inLambda), std::make_index_sequence()); @@ -90,7 +90,7 @@ namespace Common { template template - void Event::Broadcast(Args&&... inArgs) const + void Delegate::Broadcast(Args&&... inArgs) const { for (const auto& [_, receiver] : receivers) { receiver(std::forward(inArgs)...); @@ -98,7 +98,7 @@ namespace Common { } template - void Event::Unbind(ReceiverHandle inHandle) + void Delegate::Unbind(CallbackHandle inHandle) { auto iter = std::find_if(receivers.begin(), receivers.end(), [&](const auto& pair) -> bool { return pair.first == inHandle; }); Assert(iter != receivers.end()); @@ -106,13 +106,13 @@ namespace Common { } template - size_t Event::ReceiversCount() const + size_t Delegate::Count() const { return receivers.size(); } template - void Event::Reset() + void Delegate::Reset() { counter = 0; receivers.clear(); @@ -120,21 +120,21 @@ namespace Common { template template - void Event::BindStaticInternal(ReceiverHandle inHandle, std::index_sequence) + void Delegate::BindStaticInternal(CallbackHandle inHandle, std::index_sequence) { receivers.emplace_back(inHandle, std::bind(F, Internal::IndexToStdPlaceholder::value...)); } template template - void Event::BindMemberInternal(ReceiverHandle inHandle, C& inObj, std::index_sequence) + void Delegate::BindMemberInternal(CallbackHandle inHandle, C& inObj, std::index_sequence) { receivers.emplace_back(inHandle, std::bind(F, &inObj, Internal::IndexToStdPlaceholder::value...)); } template template - void Event::BindLambdaInternal(ReceiverHandle inHandle, F&& inLambda, std::index_sequence) + void Delegate::BindLambdaInternal(CallbackHandle inHandle, F&& inLambda, std::index_sequence) { receivers.emplace_back(inHandle, std::bind(inLambda, Internal::IndexToStdPlaceholder::value...)); } diff --git a/Engine/Source/Common/Src/Event.cpp b/Engine/Source/Common/Src/Event.cpp deleted file mode 100644 index 84430caec..000000000 --- a/Engine/Source/Common/Src/Event.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by johnk on 2024/11/5. -// - -#include diff --git a/Engine/Source/Common/Test/EventTest.cpp b/Engine/Source/Common/Test/DelegateTest.cpp similarity index 92% rename from Engine/Source/Common/Test/EventTest.cpp rename to Engine/Source/Common/Test/DelegateTest.cpp index fd94a5da3..97d6a948a 100644 --- a/Engine/Source/Common/Test/EventTest.cpp +++ b/Engine/Source/Common/Test/DelegateTest.cpp @@ -2,7 +2,7 @@ // Created by johnk on 2024/11/5. // -#include +#include static int counter = 0; @@ -29,7 +29,7 @@ TEST(EventTest, BasicTest) { Receiver receiver; - Event event; + Delegate event; ASSERT_EQ(event.BindStatic<&StaticReceiver>(), 0); ASSERT_EQ(event.BindMember<&Receiver::Receive>(receiver), 1); ASSERT_EQ(event.BindLambda([](int a, bool b) -> void { diff --git a/Engine/Source/Common/Test/SerializationTest.h b/Engine/Source/Common/Test/SerializationTest.h index fe394e874..706fe3327 100644 --- a/Engine/Source/Common/Test/SerializationTest.h +++ b/Engine/Source/Common/Test/SerializationTest.h @@ -11,7 +11,6 @@ #include #include #include -#include inline std::string FltToJson(float value) { @@ -36,7 +35,6 @@ inline std::string GetEndianString(std::endian e) template void PerformTypedSerializationTestWithStream( - const std::string& contextString, const std::function()>& createSerializeStream, const std::function()>& createDeserializeStream, const T& inValue) @@ -50,8 +48,6 @@ void PerformTypedSerializationTestWithStream( T value; const auto stream = createDeserializeStream(); Common::Deserialize(*stream, value); - - std::cout << "PerformTypedSerializationTestWithStream, context: " << contextString << std::endl; ASSERT_EQ(inValue, value); } } @@ -63,14 +59,12 @@ void PerformTypedSerializationTestWithEndian(const T& inValue) std::filesystem::create_directories(fileName.parent_path()); PerformTypedSerializationTestWithStream( - std::format("BinaryFile<{}, {}>", typeid(T).name(), GetEndianString(E)), []() -> Common::UniqueRef { return { new Common::BinaryFileSerializeStream(fileName.string()) }; }, []() -> Common::UniqueRef { return { new Common::BinaryFileDeserializeStream(fileName.string()) }; }, inValue); std::vector buffer; PerformTypedSerializationTestWithStream( - std::format("Memory<{}, {}>", typeid(T).name(), GetEndianString(E)), [&]() -> Common::UniqueRef { return { new Common::MemorySerializeStream(buffer) }; }, [&]() -> Common::UniqueRef { return { new Common::MemoryDeserializeStream(buffer) }; }, inValue); diff --git a/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Instance.h b/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Instance.h index 626c0167f..a7a16121f 100644 --- a/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Instance.h +++ b/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Instance.h @@ -54,8 +54,6 @@ namespace RHI::Vulkan { #endif VkInstance nativeInstance; std::vector nativePhysicalDevices; - std::vector vkEnabledExtensionNames; - std::vector vkEnabledLayerNames; std::vector> gpus; std::unordered_map dynamicFuncPointers; }; diff --git a/Engine/Source/RHI-Vulkan/Src/CommandRecorder.cpp b/Engine/Source/RHI-Vulkan/Src/CommandRecorder.cpp index e68df1c58..c219f1688 100644 --- a/Engine/Source/RHI-Vulkan/Src/CommandRecorder.cpp +++ b/Engine/Source/RHI-Vulkan/Src/CommandRecorder.cpp @@ -471,7 +471,13 @@ namespace RHI::Vulkan { void VulkanRasterPassCommandRecorder::SetPrimitiveTopology(PrimitiveTopology inPrimitiveTopology) { +#if PLATFORM_MACOS + // MoltenVK not support use vkCmdSetPrimitiveTopology() directly current + auto* pfn = device.GetGpu().GetInstance().FindOrGetTypedDynamicFuncPointer("vkCmdSetPrimitiveTopologyEXT"); + pfn(commandBuffer.GetNative(), EnumCast(inPrimitiveTopology)); +#else vkCmdSetPrimitiveTopology(commandBuffer.GetNative(), EnumCast(inPrimitiveTopology)); +#endif } void VulkanRasterPassCommandRecorder::SetBlendConstant(const float *inConstants) diff --git a/Engine/Source/RHI-Vulkan/Src/Device.cpp b/Engine/Source/RHI-Vulkan/Src/Device.cpp index c5c15a386..1814a48ad 100644 --- a/Engine/Source/RHI-Vulkan/Src/Device.cpp +++ b/Engine/Source/RHI-Vulkan/Src/Device.cpp @@ -24,17 +24,18 @@ #include namespace RHI::Vulkan { - const std::vector DEVICE_EXTENSIONS = { + const std::vector requiredExtensions = { "VK_KHR_swapchain", "VK_KHR_dynamic_rendering", "VK_KHR_depth_stencil_resolve", "VK_KHR_create_renderpass2", #if PLATFORM_MACOS - "VK_KHR_portability_subset" + "VK_KHR_portability_subset", + "VK_EXT_extended_dynamic_state" #endif }; - const std::vector VALIDATION_LAYERS = { + const std::vector requiredValidationLayers = { "VK_LAYER_KHRONOS_validation" }; } @@ -259,12 +260,20 @@ namespace RHI::Vulkan { dynamicRenderingFeatures.dynamicRendering = VK_TRUE; deviceCreateInfo.pNext = &dynamicRenderingFeatures; - deviceCreateInfo.ppEnabledExtensionNames = DEVICE_EXTENSIONS.data(); - deviceCreateInfo.enabledExtensionCount = static_cast(DEVICE_EXTENSIONS.size()); + deviceCreateInfo.ppEnabledExtensionNames = requiredExtensions.data(); + deviceCreateInfo.enabledExtensionCount = static_cast(requiredExtensions.size()); -#ifdef BUILD_CONFIG_DEBUG - deviceCreateInfo.enabledLayerCount = static_cast(VALIDATION_LAYERS.size()); - deviceCreateInfo.ppEnabledLayerNames = VALIDATION_LAYERS.data(); +#if PLATFORM_MACOS + // MoltenVK not support use vkCmdSetPrimitiveTopology() directly current + VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeatures = {}; + extendedDynamicStateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; + extendedDynamicStateFeatures.extendedDynamicState = VK_TRUE; + dynamicRenderingFeatures.pNext = &extendedDynamicStateFeatures; +#endif + +#if BUILD_CONFIG_DEBUG + deviceCreateInfo.enabledLayerCount = static_cast(requiredValidationLayers.size()); + deviceCreateInfo.ppEnabledLayerNames = requiredValidationLayers.data(); #endif Assert(vkCreateDevice(gpu.GetNative(), &deviceCreateInfo, nullptr, &nativeDevice) == VK_SUCCESS); diff --git a/Engine/Source/RHI-Vulkan/Src/Instance.cpp b/Engine/Source/RHI-Vulkan/Src/Instance.cpp index e0ecde4b6..c19574d3d 100644 --- a/Engine/Source/RHI-Vulkan/Src/Instance.cpp +++ b/Engine/Source/RHI-Vulkan/Src/Instance.cpp @@ -10,6 +10,24 @@ #include namespace RHI::Vulkan { + static std::vector requiredLayerNames = { + "VK_LAYER_KHRONOS_validation" + }; + + static std::vector requiredExtensionNames = { + "VK_KHR_surface", +#if PLATFORM_WINDOWS + "VK_KHR_win32_surface", +#elif PLATFORM_MACOS + "VK_EXT_metal_surface", + "VK_KHR_portability_enumeration", + "VK_KHR_get_physical_device_properties2", +#endif +#if BUILD_CONFIG_DEBUG + "VK_EXT_debug_utils" +#endif + }; + #if BUILD_CONFIG_DEBUG static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, @@ -66,10 +84,6 @@ namespace RHI::Vulkan { #if BUILD_CONFIG_DEBUG void VulkanInstance::PrepareLayers() { - static std::vector requiredLayerNames = { - "VK_LAYER_KHRONOS_validation" - }; - uint32_t supportedLayerCount = 0; vkEnumerateInstanceLayerProperties(&supportedLayerCount, nullptr); std::vector supportedLayers(supportedLayerCount); @@ -81,30 +95,14 @@ namespace RHI::Vulkan { [&requiredLayerName](const auto& elem) -> bool { return std::string(requiredLayerName) == elem.layerName; } ); iter == supportedLayers.end()) { - QuickFailWithReason("not found required vulkan layers"); + QuickFailWithReason("required vulkan layers is missing"); } - vkEnabledLayerNames.emplace_back(requiredLayerName); } } #endif void VulkanInstance::PrepareExtensions() { - static std::vector requiredExtensionNames = { - VK_KHR_SURFACE_EXTENSION_NAME, -#if PLATFORM_WINDOWS - "VK_KHR_win32_surface", -#elif PLATFORM_MACOS - "VK_MVK_macos_surface", - "VK_EXT_metal_surface", - VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, -#endif -#if BUILD_CONFIG_DEBUG - VK_EXT_DEBUG_UTILS_EXTENSION_NAME -#endif - }; - uint32_t supportedExtensionCount = 0; vkEnumerateInstanceExtensionProperties(nullptr, &supportedExtensionCount, nullptr); std::vector supportedExtensions(supportedExtensionCount); @@ -116,9 +114,8 @@ namespace RHI::Vulkan { [&requiredExtensionName](const auto& elem) -> bool { return std::string(requiredExtensionName) == elem.extensionName; } ); iter == supportedExtensions.end()) { - continue; + QuickFailWithReason("required vulkan extensions is not support"); } - vkEnabledExtensionNames.emplace_back(requiredExtensionName); } } @@ -134,11 +131,11 @@ namespace RHI::Vulkan { VkInstanceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pApplicationInfo = &applicationInfo; - createInfo.enabledExtensionCount = vkEnabledExtensionNames.size(); - createInfo.ppEnabledExtensionNames = vkEnabledExtensionNames.data(); + createInfo.enabledExtensionCount = requiredExtensionNames.size(); + createInfo.ppEnabledExtensionNames = requiredExtensionNames.data(); #if BUILD_CONFIG_DEBUG - createInfo.enabledLayerCount = vkEnabledLayerNames.size(); - createInfo.ppEnabledLayerNames = vkEnabledLayerNames.data(); + createInfo.enabledLayerCount = requiredLayerNames.size(); + createInfo.ppEnabledLayerNames = requiredLayerNames.data(); VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {}; PopulateDebugMessengerCreateInfo(debugCreateInfo); diff --git a/Engine/Source/RHI-Vulkan/Src/Platform/MacosSurface.mm b/Engine/Source/RHI-Vulkan/Src/Platform/MacosSurface.mm index 88f8a03f9..65c3a8d8c 100644 --- a/Engine/Source/RHI-Vulkan/Src/Platform/MacosSurface.mm +++ b/Engine/Source/RHI-Vulkan/Src/Platform/MacosSurface.mm @@ -8,7 +8,7 @@ #include #include -#define VK_USE_PLATFORM_MACOS_MVK +#define VK_USE_PLATFORM_METAL_EXT #include namespace RHI::Vulkan { @@ -22,14 +22,12 @@ VkSurfaceKHR CreateNativeSurface(const VkInstance& instance, const SurfaceCreate [view setLayer: layer]; [view setWantsLayer: YES]; - VkMacOSSurfaceCreateInfoMVK surfaceInfo = {}; - surfaceInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; - surfaceInfo.pView = view; - surfaceInfo.pNext = nullptr; - surfaceInfo.flags = 0; + VkMetalSurfaceCreateInfoEXT surfaceInfo = {}; + surfaceInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; + surfaceInfo.pLayer = static_cast(layer); VkSurfaceKHR surface = VK_NULL_HANDLE; - vkCreateMacOSSurfaceMVK(instance, &surfaceInfo, nullptr, &surface); + vkCreateMetalSurfaceEXT(instance, &surfaceInfo, nullptr, &surface); return surface; } } diff --git a/Engine/Source/RHI/Include/RHI/Instance.h b/Engine/Source/RHI/Include/RHI/Instance.h index 6bbf3e6d2..63b619f9e 100644 --- a/Engine/Source/RHI/Include/RHI/Instance.h +++ b/Engine/Source/RHI/Include/RHI/Instance.h @@ -15,7 +15,8 @@ namespace RHI { RHIType GetPlatformRHIType(); std::string GetPlatformDefaultRHIAbbrString(); - RHIType RHIAbbrStringToRHIType(const std::string& abbrString); + std::string GetAbbrStringByType(RHIType type); + RHIType GetRHITypeByAbbrString(const std::string& abbrString); std::string GetRHIModuleNameByType(RHIType type); class Instance { diff --git a/Engine/Source/RHI/Src/Instance.cpp b/Engine/Source/RHI/Src/Instance.cpp index 6811d9771..264964798 100644 --- a/Engine/Source/RHI/Src/Instance.cpp +++ b/Engine/Source/RHI/Src/Instance.cpp @@ -24,7 +24,17 @@ namespace RHI { #endif } - RHIType RHIAbbrStringToRHIType(const std::string& abbrString) + std::string GetAbbrStringByType(RHIType type) + { + static std::unordered_map map = { + { RHIType::directX12, "dx12" }, + { RHIType::vulkan, "vulkan" }, + { RHIType::dummy, "dummy" } + }; + return map.at(type); + } + + RHIType GetRHITypeByAbbrString(const std::string& abbrString) // NOLINT { static std::unordered_map map = { { "dx12", RHIType::directX12 }, diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h index 41f28ab80..51f6b0fa0 100644 --- a/Engine/Source/Runtime/Include/Runtime/ECS.h +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -7,11 +7,12 @@ #include #include -#include +#include #include #include #include #include +#include namespace Runtime { using Entity = size_t; @@ -23,13 +24,16 @@ namespace Runtime { class ECRegistry; - class EClass() System { + template + concept ECRegistryOrConst = std::is_same_v, ECRegistry>; + + class RUNTIME_API EClass() System { public: EClassBody(System) explicit System(ECRegistry& inRegistry); virtual ~System(); - virtual void Execute(float inDeltaTimeMs); + virtual void Tick(float inDeltaTimeMs); protected: ECRegistry& registry; @@ -41,14 +45,14 @@ namespace Runtime::Internal { using ElemPtr = void*; template const Mirror::Class* GetClass(); - template struct LambdaTraits; + template struct MemberFuncPtrTraits; class CompRtti { public: explicit CompRtti(CompClass inClass); void Bind(size_t inOffset); - Mirror::Any MoveConstruct(ElemPtr inElem, const Mirror::Argument& inOther) const; - Mirror::Any MoveAssign(ElemPtr inElem, const Mirror::Argument& inOther) const; + Mirror::Any MoveConstruct(ElemPtr inElem, const Mirror::Any& inOther) const; + Mirror::Any MoveAssign(ElemPtr inElem, const Mirror::Any& inOther) const; void Destruct(ElemPtr inElem) const; Mirror::Any Get(ElemPtr inElem) const; CompClass Class() const; @@ -67,16 +71,16 @@ namespace Runtime::Internal { size_t offset; }; - class Archetype { + class RUNTIME_API Archetype { public: explicit Archetype(const std::vector& inRttiVec); bool Contains(CompClass inClazz) const; bool ContainsAll(const std::vector& inClasses) const; - bool NotContainsAny(const std::vector& inCompClasses) const; + bool NotContainsAny(const std::vector& inClasses) const; ElemPtr EmplaceElem(Entity inEntity); ElemPtr EmplaceElem(Entity inEntity, ElemPtr inSrcElem, const std::vector& inSrcRttiVec); - Mirror::Any EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Argument& inCompRef); + Mirror::Any EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Any& inCompRef); void EraseElem(Entity inEntity); ElemPtr GetElem(Entity inEntity) const; Mirror::Any GetComp(Entity inEntity, CompClass inCompClass); @@ -184,7 +188,7 @@ namespace Runtime { G& globalCompRef; }; - class ScopedUpdaterDyn { + class RUNTIME_API ScopedUpdaterDyn { public: ScopedUpdaterDyn(ECRegistry& inRegistry, CompClass inClass, Entity inEntity, const Mirror::Any& inCompRef); ~ScopedUpdaterDyn(); @@ -198,10 +202,10 @@ namespace Runtime { ECRegistry& registry; CompClass clazz; Entity entity; - const Mirror::Any& compRef; + Mirror::Any compRef; }; - class GScopedUpdaterDyn { + class RUNTIME_API GScopedUpdaterDyn { public: GScopedUpdaterDyn(ECRegistry& inRegistry, GCompClass inClass, const Mirror::Any& inGlobalCompRef); ~GScopedUpdaterDyn(); @@ -214,7 +218,7 @@ namespace Runtime { private: ECRegistry& registry; GCompClass clazz; - const Mirror::Any& globalCompRef; + Mirror::Any globalCompRef; }; template @@ -224,73 +228,82 @@ namespace Runtime { struct Exclude {}; template - class View; + class BasicView; - template - class View, C...> { + template + class BasicView, C...> { public: - explicit View(ECRegistry& inRegistry); - NonCopyable(View) - NonMovable(View) + using ResultVector = std::vector>; + using ConstIter = typename ResultVector::const_iterator; + + explicit BasicView(R& inRegistry); + NonCopyable(BasicView) + NonMovable(BasicView) template void Each(F&& inFunc) const; - auto Begin(); - auto Begin() const; - auto End(); - auto End() const; - auto begin(); - auto begin() const; - auto end(); - auto end() const; + size_t Size() const; + ConstIter Begin() const; + ConstIter End() const; + ConstIter begin() const; + ConstIter end() const; private: - void Evaluate(ECRegistry& inRegistry); + void Evaluate(R& inRegistry); - std::vector> result; + ResultVector result; }; - class RuntimeViewRule { + template using View = BasicView; + template using ConstView = BasicView; + + class RUNTIME_API RuntimeFilter { public: - RuntimeViewRule(); - template RuntimeViewRule& Include(); - template RuntimeViewRule& Exclude(); - RuntimeViewRule& IncludeDyn(CompClass inClass); - RuntimeViewRule& ExcludeDyn(CompClass inClass); + RuntimeFilter(); + template RuntimeFilter& Include(); + template RuntimeFilter& Exclude(); + RuntimeFilter& IncludeDyn(CompClass inClass); + RuntimeFilter& ExcludeDyn(CompClass inClass); private: - friend class RuntimeView; + template friend class BasicRuntimeView; std::unordered_set includes; std::unordered_set excludes; }; - class RuntimeView { + template + class BasicRuntimeView { public: - explicit RuntimeView(ECRegistry& inRegistry, const RuntimeViewRule& inArgs); - NonCopyable(RuntimeView) - NonMovable(RuntimeView) + using ResultEntitiesVector = std::vector; + using ConstIter = typename ResultEntitiesVector::const_iterator; + + explicit BasicRuntimeView(R& inRegistry, const RuntimeFilter& inFilter); + NonCopyable(BasicRuntimeView) + NonMovable(BasicRuntimeView) template void Each(F&& inFunc) const; - auto Begin(); - auto Begin() const; - auto End(); - auto End() const; - auto begin(); - auto begin() const; - auto end(); - auto end() const; + size_t Size() const; + ConstIter Begin() const; + ConstIter End() const; + ConstIter begin() const; + ConstIter end() const; private: - template void InvokeTraverseFuncInternal(F&& inFunc, std::pair>& inEntityAndComps, std::index_sequence) const; - template decltype(auto) GetCompRef(std::vector& inComps) const; - void Evaluate(ECRegistry& inRegistry, const RuntimeViewRule& inArgs); + using ResultVector = std::vector>>; + + template void InvokeTraverseFuncInternal(F&& inFunc, const std::pair>& inEntityAndComps, std::index_sequence) const; + template decltype(auto) GetCompRef(const std::vector& inComps) const; + void Evaluate(R& inRegistry, const RuntimeFilter& inFilter); std::unordered_map slotMap; - std::vector resultEntities; - std::vector>> result; + ResultEntitiesVector resultEntities; + ResultVector result; }; - class Observer { + using RuntimeView = BasicRuntimeView; + using ConstRuntimeView = BasicRuntimeView; + + class RUNTIME_API Observer { public: using ConstIter = std::vector::const_iterator; using EntityTraverseFunc = Internal::EntityPool::EntityTraverseFunc; @@ -301,33 +314,35 @@ namespace Runtime { NonCopyable(Observer) NonMovable(Observer) - template void ObConstructed(); - template void ObUpdated(); - template void ObRemove(); + template Observer& ObConstructed(); + template Observer& ObUpdated(); + Observer& ObConstructedDyn(CompClass inClass); + Observer& ObUpdatedDyn(CompClass inClass); + size_t Size() const; void Each(const EntityTraverseFunc& inFunc) const; void Clear(); - void Reset(); + void UnbindAll(); ConstIter Begin() const; ConstIter End() const; ConstIter begin() const; ConstIter end() const; private: - void OnEvent(Common::Event& inEvent); + Observer& OnEvent(Common::Delegate& inEvent); void RecordEntity(ECRegistry& inRegistry, Entity inEntity); ECRegistry& registry; - std::vector> receiverHandles; + std::vector> receiverHandles; std::vector entities; }; - class MIRROR_API ECRegistry { + class RUNTIME_API ECRegistry { public: using EntityTraverseFunc = Internal::EntityPool::EntityTraverseFunc; using DynUpdateFunc = std::function; using ConstIter = Internal::EntityPool::ConstIter; - using CompEvent = Common::Event; - using GCompEvent = Common::Event; + using CompEvent = Common::Delegate; + using GCompEvent = Common::Delegate; struct CompEvents { CompEvent onConstructed; @@ -374,7 +389,9 @@ namespace Runtime { template const C* Find(Entity inEntity) const; template C& Get(Entity inEntity); template const C& Get(Entity inEntity) const; - template View, C...> View(Exclude); + template Runtime::View, C...> View(Exclude = {}); + template Runtime::ConstView, C...> View(Exclude = {}) const; + template Runtime::ConstView, C...> ConstView(Exclude = {}) const; template CompEvents& Events(); Observer Observer(); @@ -390,7 +407,9 @@ namespace Runtime { Mirror::Any GetDyn(CompClass inClass, Entity inEntity); Mirror::Any GetDyn(CompClass inClass, Entity inEntity) const; CompEvents& EventsDyn(CompClass inClass); - RuntimeView RuntimeView(const RuntimeViewRule& inRule); + Runtime::RuntimeView RuntimeView(const RuntimeFilter& inFilter); + Runtime::ConstRuntimeView RuntimeView(const RuntimeFilter& inFilter) const; + Runtime::ConstRuntimeView ConstRuntimeView(const RuntimeFilter& inFilter) const; // global component static template G& GEmplace(Args&&... inArgs); @@ -419,8 +438,8 @@ namespace Runtime { GCompEvents& GEventsDyn(GCompClass inClass); private: - template friend class View; - friend class RuntimeView; + template friend class BasicView; + template friend class BasicRuntimeView; template void NotifyConstructed(Entity inEntity); template void NotifyRemove(Entity inEntity); @@ -439,29 +458,43 @@ namespace Runtime { std::unordered_map globalCompEvents; }; - class SystemGroup { - public: - explicit SystemGroup(std::string inName); + enum class SystemExecuteStrategy : uint8_t { + sequential, + concurrent, + max + }; - Internal::SystemFactory& EmplaceSystem(SystemClass inClass); - void RemoveSystem(SystemClass inClass); - bool HasSystem(SystemClass inClass) const; - Internal::SystemFactory& GetSystem(SystemClass inClass); - const Internal::SystemFactory& GetSystem(SystemClass inClass) const; + class RUNTIME_API SystemGroup { + public: + explicit SystemGroup(std::string inName, SystemExecuteStrategy inStrategy); + + template Internal::SystemFactory& EmplaceSystem(); + template void RemoveSystem(); + template bool HasSystem() const; + template Internal::SystemFactory& GetSystem(); + template const Internal::SystemFactory& GetSystem() const; + + Internal::SystemFactory& EmplaceSystemDyn(SystemClass inClass); + void RemoveSystemDyn(SystemClass inClass); + bool HasSystemDyn(SystemClass inClass) const; + Internal::SystemFactory& GetSystemDyn(SystemClass inClass); + const Internal::SystemFactory& GetSystemDyn(SystemClass inClass) const; auto GetSystems(); auto GetSystems() const; const std::string& GetName() const; + SystemExecuteStrategy GetStrategy() const; private: std::string name; + SystemExecuteStrategy strategy; std::unordered_map systems; }; - class SystemGraph { + class RUNTIME_API SystemGraph { public: SystemGraph(); - SystemGroup& AddGroup(const std::string& inName); + SystemGroup& AddGroup(const std::string& inName, SystemExecuteStrategy inStrategy); void RemoveGroup(const std::string& inName); bool HasGroup(const std::string& inName) const; SystemGroup& GetGroup(const std::string& inName); @@ -481,13 +514,18 @@ namespace Runtime { const Internal::SystemFactory& factory; Common::UniqueRef instance; }; - using ActionFunc = std::function; - void ParallelPerformAction(const ActionFunc& inActionFunc); + struct SystemGroupContext { + std::vector systems; + SystemExecuteStrategy strategy; + }; friend class SystemGraphExecutor; + using ActionFunc = std::function; - std::vector> systemGraph; + void ParallelPerformAction(const ActionFunc& inActionFunc); + + std::vector systemGraph; }; class SystemGraphExecutor { @@ -514,10 +552,18 @@ namespace Runtime::Internal { return &Mirror::Class::Get(); } - template - struct LambdaTraits> { - static constexpr auto ArgSize = sizeof...(T); - using ArgsTupleType = std::tuple; + template + struct MemberFuncPtrTraits { + static constexpr auto ArgSize = sizeof...(Args); + using ClassType = Class; + using ArgsTupleType = std::tuple; + }; + + template + struct MemberFuncPtrTraits { + static constexpr auto ArgSize = sizeof...(Args); + using ClassType = const Class; + using ArgsTupleType = std::tuple; }; inline auto Archetype::All() const @@ -578,82 +624,68 @@ namespace Runtime { return globalCompRef.As(); } - template - View, C...>::View(ECRegistry& inRegistry) + template + BasicView, C...>::BasicView(R& inRegistry) { Evaluate(inRegistry); } - template + template template - void View, C...>::Each(F&& inFunc) const + void BasicView, C...>::Each(F&& inFunc) const { - for (const auto& entity : result) { - std::apply(inFunc, entity); + for (const auto& entityAndComps : result) { + if constexpr (Internal::MemberFuncPtrTraits::ArgSize == 1) { + inFunc(std::get<0>(entityAndComps)); + } else { + std::apply(inFunc, entityAndComps); + } } } - template - auto View, C...>::Begin() + template + size_t BasicView, C...>::Size() const { - return result.begin(); + return result.size(); } - template - auto View, C...>::Begin() const + template + typename BasicView, C...>::ConstIter BasicView, C...>::Begin() const { return result.begin(); } - template - auto View, C...>::End() + template + typename BasicView, C...>::ConstIter BasicView, C...>::End() const { return result.end(); } - template - auto View, C...>::End() const - { - return result.end(); - } - - template - auto View, C...>::begin() - { - return Begin(); - } - - template - auto View, C...>::begin() const + template + typename BasicView, C...>::ConstIter BasicView, C...>::begin() const { return Begin(); } - template - auto View, C...>::end() - { - return End(); - } - - template - auto View, C...>::end() const + template + typename BasicView, C...>::ConstIter BasicView, C...>::end() const { return End(); } - template - void View, C...>::Evaluate(ECRegistry& inRegistry) + template + void BasicView, C...>::Evaluate(R& inRegistry) { std::vector includeCompIds; includeCompIds.reserve(sizeof...(C)); (void) std::initializer_list { ([&]() -> void { - includeCompIds.emplace_back(Internal::GetClass()); + includeCompIds.emplace_back(Internal::GetClass>()); }(), 0)... }; std::vector excludeCompIds; excludeCompIds.reserve(sizeof...(E)); (void) std::initializer_list { ([&]() -> void { - excludeCompIds.emplace_back(Internal::GetClass()); + excludeCompIds.emplace_back(Internal::GetClass()); }(), 0)... }; for (auto& archetype : inRegistry.archetypes | std::views::values) { @@ -663,35 +695,107 @@ namespace Runtime { result.reserve(result.size() + archetype.Size()); for (auto entity : archetype.All()) { - result.emplace_back(entity, inRegistry.Get(entity)...); + result.emplace_back(entity, inRegistry.template Get>(entity)...); } } } + template + BasicRuntimeView::BasicRuntimeView(R& inRegistry, const RuntimeFilter& inFilter) + { + Evaluate(inRegistry, inFilter); + } + + template template - void RuntimeView::Each(F&& inFunc) const + void BasicRuntimeView::Each(F&& inFunc) const { + using Traits = Internal::MemberFuncPtrTraits; + for (const auto& pair : result) { - InvokeTraverseFuncInternal::ArgsTupleType>(std::forward(inFunc), pair, std::make_index_sequence::ArgSize> {}); + InvokeTraverseFuncInternal(std::forward(inFunc), pair, std::make_index_sequence {}); } } + template + size_t BasicRuntimeView::Size() const + { + return resultEntities.size(); + } + + template + typename BasicRuntimeView::ConstIter BasicRuntimeView::Begin() const + { + return resultEntities.begin(); + } + + template + typename BasicRuntimeView::ConstIter BasicRuntimeView::End() const + { + return resultEntities.end(); + } + + template + typename BasicRuntimeView::ConstIter BasicRuntimeView::begin() const + { + return Begin(); + } + + template + typename BasicRuntimeView::ConstIter BasicRuntimeView::end() const + { + return End(); + } + + template template - void RuntimeView::InvokeTraverseFuncInternal(F&& inFunc, std::pair>& inEntityAndComps, std::index_sequence) const + void BasicRuntimeView::InvokeTraverseFuncInternal(F&& inFunc, const std::pair>& inEntityAndComps, std::index_sequence) const { - inFunc(inEntityAndComps.first, GetCompRef>(inEntityAndComps.second)...); + inFunc(inEntityAndComps.first, GetCompRef>(inEntityAndComps.second)...); } + template template - decltype(auto) RuntimeView::GetCompRef(std::vector& inComps) const + decltype(auto) BasicRuntimeView::GetCompRef(const std::vector& inComps) const { static_assert(std::is_reference_v); - const auto compIndex = slotMap.at(Internal::GetClass()); + const auto compIndex = slotMap.at(Internal::GetClass>()); return inComps[compIndex].template As(); } + template + void BasicRuntimeView::Evaluate(R& inRegistry, const RuntimeFilter& inFilter) + { + const std::vector includes(inFilter.includes.begin(), inFilter.includes.end()); + const std::vector excludes(inFilter.excludes.begin(), inFilter.excludes.end()); + + slotMap.reserve(includes.size()); + for (auto i = 0; i < includes.size(); i++) { + slotMap.emplace(includes[i], i); + } + + for (auto& archetype : inRegistry.archetypes | std::views::values) { + if (!archetype.ContainsAll(includes) || !archetype.NotContainsAny(excludes)) { + continue; + } + + resultEntities.reserve(result.size() + archetype.Size()); + result.reserve(result.size() + archetype.Size()); + for (const auto entity : archetype.All()) { + std::vector comps; + comps.reserve(includes.size()); + for (const auto clazz : includes) { + comps.emplace_back(archetype.GetComp(entity, clazz)); + } + + resultEntities.emplace_back(entity); + result.emplace_back(entity, std::move(comps)); + } + } + } + template - RuntimeViewRule& RuntimeViewRule::Include() + RuntimeFilter& RuntimeFilter::Include() { const auto* clazz = Internal::GetClass(); Assert(!includes.contains(clazz)); @@ -700,7 +804,7 @@ namespace Runtime { } template - RuntimeViewRule& RuntimeViewRule::Exclude() + RuntimeFilter& RuntimeFilter::Exclude() { const auto* clazz = Internal::GetClass(); Assert(!excludes.contains(clazz)); @@ -709,21 +813,15 @@ namespace Runtime { } template - void Observer::ObConstructed() - { - OnEvent(registry.Events().onConstructed); - } - - template - void Observer::ObUpdated() + Observer& Observer::ObConstructed() { - OnEvent(registry.Events().onUpdated); + return OnEvent(registry.Events().onConstructed); } template - void Observer::ObRemove() + Observer& Observer::ObUpdated() { - OnEvent(registry.Events().onRemove); + return OnEvent(registry.Events().onUpdated); } template @@ -741,13 +839,15 @@ namespace Runtime { template void ECRegistry::Update(Entity inEntity, F&& inFunc) { - UpdateDyn(Internal::GetClass(), inEntity, std::forward(inFunc)); + UpdateDyn(Internal::GetClass(), inEntity, [&](const Mirror::Any& ref) -> void { + inFunc(ref.As()); + }); } template ScopedUpdater ECRegistry::Update(Entity inEntity) { - Assert(Valid(inEntity) && Has()); + Assert(Valid(inEntity) && Has(inEntity)); return { *this, inEntity, Get(inEntity) }; } @@ -782,9 +882,21 @@ namespace Runtime { } template - View, C...> ECRegistry::View(Exclude) + Runtime::View, C...> ECRegistry::View(Exclude) { - return { *this }; + return Runtime::View, C...>(*this); + } + + template + Runtime::ConstView, C...> ECRegistry::View(Exclude) const + { + return Runtime::ConstView, C...>(*this); + } + + template + Runtime::ConstView, C...> ECRegistry::ConstView(Exclude) const + { + return Runtime::ConstView, C...>(*this); } template @@ -814,7 +926,7 @@ namespace Runtime { template G& ECRegistry::GEmplace(Args&&... inArgs) { - return GEmplaceDyn(Internal::GetClass(), Mirror::ForwardAsArgList(std::forward(inArgs)...)); + return GEmplaceDyn(Internal::GetClass(), Mirror::ForwardAsArgList(std::forward(inArgs)...)).template As(); } template @@ -826,7 +938,9 @@ namespace Runtime { template void ECRegistry::GUpdate(F&& inFunc) { - GUpdateDyn(Internal::GetClass(), std::forward(inFunc)); + GUpdateDyn(Internal::GetClass(), [&](const Mirror::Any& ref) -> void { + inFunc(ref.As()); + }); } template @@ -889,4 +1003,34 @@ namespace Runtime { { GNotifyRemoveDyn(Internal::GetClass()); } + + template + Internal::SystemFactory& SystemGroup::EmplaceSystem() + { + return EmplaceSystemDyn(Internal::GetClass()); + } + + template + void SystemGroup::RemoveSystem() + { + RemoveSystemDyn(Internal::GetClass()); + } + + template + bool SystemGroup::HasSystem() const + { + return HasSystemDyn(Internal::GetClass()); + } + + template + Internal::SystemFactory& SystemGroup::GetSystem() + { + return GetSystemDyn(Internal::GetClass()); + } + + template + const Internal::SystemFactory& SystemGroup::GetSystem() const + { + return GetSystemDyn(Internal::GetClass()); + } } // namespace Runtime diff --git a/Engine/Source/Runtime/Include/Runtime/Engine.h b/Engine/Source/Runtime/Include/Runtime/Engine.h index a0fae201a..c72380abf 100644 --- a/Engine/Source/Runtime/Include/Runtime/Engine.h +++ b/Engine/Source/Runtime/Include/Runtime/Engine.h @@ -27,7 +27,7 @@ namespace Runtime { void MountWorld(World* inWorld); void UnmountWorld(World* inWorld); Render::RenderModule& GetRenderModule() const; - void Tick(float inTimeMs) const; + void Tick(float inTimeSeconds) const; Common::UniqueRef CreateWorld(const std::string& inName = "") const; protected: @@ -45,7 +45,7 @@ namespace Runtime { bool IsEditor() override; }; - struct RUNTIME_API IGameModule : Core::Module { // NOLINT + struct RUNTIME_API IEngineModule : Core::Module { // NOLINT virtual Engine* CreateEngine(const EngineInitParams& inParams) = 0; }; @@ -56,6 +56,6 @@ namespace Runtime { static Engine& Get(); private: - static Engine* engine; + static Common::UniqueRef engine; }; } diff --git a/Engine/Source/Runtime/Include/Runtime/World.h b/Engine/Source/Runtime/Include/Runtime/World.h index 976ae53df..5194d1ad5 100644 --- a/Engine/Source/Runtime/Include/Runtime/World.h +++ b/Engine/Source/Runtime/Include/Runtime/World.h @@ -18,17 +18,12 @@ namespace Runtime { max }; - class World { + class RUNTIME_API World { public: NonCopyable(World) NonMovable(World) ~World(); - private: - friend class Engine; - - explicit World(const std::string& inName = ""); - void SetSystemGraph(const SystemGraph& inSystemGraph); void Reset(); PlayStatus PlayStatus() const; @@ -39,6 +34,11 @@ namespace Runtime { void Resume(); void Pause(); void Stop(); + + private: + friend class Engine; + + explicit World(const std::string& inName = ""); void Tick(float inTimeMs); std::string name; diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp index 05a875f22..707968410 100644 --- a/Engine/Source/Runtime/Src/ECS.cpp +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -14,7 +14,7 @@ namespace Runtime { System::~System() = default; - void System::Execute(float inDeltaTimeMs) {} + void System::Tick(float inDeltaTimeMs) {} } namespace Runtime::Internal { @@ -31,13 +31,13 @@ namespace Runtime::Internal { offset = inOffset; } - Mirror::Any CompRtti::MoveConstruct(ElemPtr inElem, const Mirror::Argument& inOther) const + Mirror::Any CompRtti::MoveConstruct(ElemPtr inElem, const Mirror::Any& inOther) const { auto* compBegin = static_cast(inElem) + offset; return clazz->InplaceNewDyn(compBegin, { inOther }); } - Mirror::Any CompRtti::MoveAssign(ElemPtr inElem, const Mirror::Argument& inOther) const + Mirror::Any CompRtti::MoveAssign(ElemPtr inElem, const Mirror::Any& inOther) const { auto* compBegin = static_cast(inElem) + offset; auto compRef = clazz->InplaceGetObject(compBegin); @@ -102,18 +102,18 @@ namespace Runtime::Internal { bool Archetype::ContainsAll(const std::vector& inClasses) const { - for (const auto& rtti : rttiVec) { - if (!Contains(rtti.Class())) { + for (const auto& clazz : inClasses) { + if (!Contains(clazz)) { return false; } } return true; } - bool Archetype::NotContainsAny(const std::vector& inCompClasses) const + bool Archetype::NotContainsAny(const std::vector& inClasses) const { - for (const auto& rtti : rttiVec) { - if (Contains(rtti.Class())) { + for (const auto& clazz : inClasses) { + if (Contains(clazz)) { return false; } } @@ -142,7 +142,7 @@ namespace Runtime::Internal { return newElem; } - Mirror::Any Archetype::EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Argument& inCompRef) // NOLINT + Mirror::Any Archetype::EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Any& inCompRef) // NOLINT { ElemPtr elem = ElemAt(entityMap.at(inEntity)); return GetCompRtti(inCompClass).MoveConstruct(elem, inCompRef); @@ -162,6 +162,7 @@ namespace Runtime::Internal { entityMap.erase(inEntity); elemMap.at(elemIndex) = entityToLastElem; elemMap.erase(lastElemIndex); + size--; } ElemPtr Archetype::GetElem(Entity inEntity) const @@ -403,103 +404,43 @@ namespace Runtime { registry.GNotifyUpdatedDyn(clazz); } - RuntimeViewRule::RuntimeViewRule() = default; + RuntimeFilter::RuntimeFilter() = default; - RuntimeViewRule& RuntimeViewRule::IncludeDyn(CompClass inClass) + RuntimeFilter& RuntimeFilter::IncludeDyn(CompClass inClass) { includes.emplace(inClass); return *this; } - RuntimeViewRule& RuntimeViewRule::ExcludeDyn(CompClass inClass) + RuntimeFilter& RuntimeFilter::ExcludeDyn(CompClass inClass) { excludes.emplace(inClass); return *this; } - RuntimeView::RuntimeView(ECRegistry& inRegistry, const RuntimeViewRule& inArgs) - { - Evaluate(inRegistry, inArgs); - } - - auto RuntimeView::Begin() - { - return resultEntities.begin(); - } - - auto RuntimeView::Begin() const - { - return resultEntities.begin(); - } - - auto RuntimeView::End() - { - return resultEntities.end(); - } - - auto RuntimeView::End() const + Observer::Observer(ECRegistry& inRegistry) + : registry(inRegistry) { - return resultEntities.end(); } - auto RuntimeView::begin() + Observer::~Observer() { - return Begin(); + UnbindAll(); } - auto RuntimeView::begin() const + Observer& Observer::ObConstructedDyn(CompClass inClass) { - return Begin(); + return OnEvent(registry.EventsDyn(inClass).onConstructed); } - auto RuntimeView::end() + Observer& Observer::ObUpdatedDyn(CompClass inClass) { - return End(); + return OnEvent(registry.EventsDyn(inClass).onUpdated); } - auto RuntimeView::end() const + size_t Observer::Size() const { - return End(); - } - - void RuntimeView::Evaluate(ECRegistry& inRegistry, const RuntimeViewRule& inArgs) - { - const std::vector includes(inArgs.includes.begin(), inArgs.includes.end()); - const std::vector excludes(inArgs.excludes.begin(), inArgs.excludes.end()); - - slotMap.reserve(includes.size()); - for (auto i = 0; i < includes.size(); i++) { - slotMap.emplace(includes[i], i); - } - - for (auto& [_, archetype] : inRegistry.archetypes) { - if (!archetype.ContainsAll(includes) || !archetype.NotContainsAny(excludes)) { - continue; - } - - resultEntities.reserve(result.size() + archetype.Size()); - result.reserve(result.size() + archetype.Size()); - for (const auto entity : archetype.All()) { - std::vector comps; - comps.reserve(includes.size()); - for (const auto clazz : includes) { - comps.emplace_back(archetype.GetComp(entity, clazz)); - } - - resultEntities.emplace_back(entity); - result.emplace_back(entity, std::move(comps)); - } - } - } - - Observer::Observer(ECRegistry& inRegistry) - : registry(inRegistry) - { - } - - Observer::~Observer() - { - Reset(); + return entities.size(); } void Observer::Each(const EntityTraverseFunc& inFunc) const @@ -514,9 +455,9 @@ namespace Runtime { entities.clear(); } - void Observer::Reset() + void Observer::UnbindAll() { - for (auto& [handle, deleter] : receiverHandles) { + for (auto& deleter : receiverHandles | std::views::values) { deleter(); } receiverHandles.clear(); @@ -547,14 +488,15 @@ namespace Runtime { entities.emplace_back(inEntity); } - void Observer::OnEvent(Common::Event& inEvent) + Observer& Observer::OnEvent(Common::Delegate& inEvent) { const auto handle = inEvent.BindMember<&Observer::RecordEntity>(*this); receiverHandles.emplace_back( handle, - [&]() -> void { + [&inEvent, handle]() -> void { inEvent.Unbind(handle); }); + return *this; } ECRegistry::ECRegistry() @@ -660,9 +602,19 @@ namespace Runtime { return End(); } - RuntimeView ECRegistry::RuntimeView(const RuntimeViewRule& inRule) + Runtime::RuntimeView ECRegistry::RuntimeView(const RuntimeFilter& inFilter) { - return Runtime::RuntimeView { *this, inRule }; + return Runtime::RuntimeView { *this, inFilter }; + } + + Runtime::ConstRuntimeView ECRegistry::RuntimeView(const RuntimeFilter& inFilter) const + { + return Runtime::ConstRuntimeView { *this, inFilter }; + } + + Runtime::ConstRuntimeView ECRegistry::ConstRuntimeView(const RuntimeFilter& inFilter) const + { + return Runtime::ConstRuntimeView { *this, inFilter }; } void ECRegistry::NotifyUpdatedDyn(CompClass inClass, Entity inEntity) @@ -706,19 +658,15 @@ namespace Runtime { const Internal::ArchetypeId newArchetypeId = archetypeId + inClass->GetTypeInfo()->id; entities.SetArchetype(inEntity, newArchetypeId); - Internal::Archetype* newArchetype; - if (archetypes.contains(newArchetypeId)) { - newArchetype = &archetypes.at(newArchetypeId); - newArchetype->EmplaceElem(inEntity, archetype.GetElem(inEntity), archetype.GetRttiVec()); - archetype.EraseElem(inEntity); - } else { + if (!archetypes.contains(newArchetypeId)) { archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewRttiVecByAdd(Internal::CompRtti(inClass)))); - newArchetype = &archetypes.at(newArchetypeId); - newArchetype->EmplaceElem(inEntity); } + Internal::Archetype& newArchetype = archetypes.at(newArchetypeId); + newArchetype.EmplaceElem(inEntity, archetype.GetElem(inEntity), archetype.GetRttiVec()); + archetype.EraseElem(inEntity); Mirror::Any tempObj = inClass->ConstructDyn(inArgs); - Mirror::Any compRef = newArchetype->EmplaceComp(inEntity, inClass, tempObj.Ref()); + Mirror::Any compRef = newArchetype.EmplaceComp(inEntity, inClass, tempObj.Ref()); NotifyConstructedDyn(inClass, inEntity); return compRef; } @@ -868,7 +816,7 @@ namespace Runtime { Mirror::Any ECRegistry::GGetDyn(GCompClass inClass) { Assert(GHasDyn(inClass)); - return globalComps.at(inClass); + return globalComps.at(inClass).Ref(); } Mirror::Any ECRegistry::GGetDyn(GCompClass inClass) const @@ -882,33 +830,34 @@ namespace Runtime { return globalCompEvents[inClass]; } - SystemGroup::SystemGroup(std::string inName) + SystemGroup::SystemGroup(std::string inName, SystemExecuteStrategy inStrategy) : name(std::move(inName)) + , strategy(inStrategy) { } - Internal::SystemFactory& SystemGroup::EmplaceSystem(SystemClass inClass) + Internal::SystemFactory& SystemGroup::EmplaceSystemDyn(SystemClass inClass) { systems.emplace(inClass, Internal::SystemFactory(inClass)); return systems.at(inClass); } - void SystemGroup::RemoveSystem(SystemClass inClass) + void SystemGroup::RemoveSystemDyn(SystemClass inClass) { systems.erase(inClass); } - bool SystemGroup::HasSystem(SystemClass inClass) const + bool SystemGroup::HasSystemDyn(SystemClass inClass) const { return systems.contains(inClass); } - Internal::SystemFactory& SystemGroup::GetSystem(SystemClass inClass) + Internal::SystemFactory& SystemGroup::GetSystemDyn(SystemClass inClass) { return systems.at(inClass); } - const Internal::SystemFactory& SystemGroup::GetSystem(SystemClass inClass) const + const Internal::SystemFactory& SystemGroup::GetSystemDyn(SystemClass inClass) const { return systems.at(inClass); } @@ -928,11 +877,16 @@ namespace Runtime { return name; } + SystemExecuteStrategy SystemGroup::GetStrategy() const + { + return strategy; + } + SystemGraph::SystemGraph() = default; - SystemGroup& SystemGraph::AddGroup(const std::string& inName) + SystemGroup& SystemGraph::AddGroup(const std::string& inName, SystemExecuteStrategy inStrategy) { - return systemGroups.emplace_back(inName); + return systemGroups.emplace_back(inName, inStrategy); } void SystemGraph::RemoveGroup(const std::string& inName) @@ -987,12 +941,13 @@ namespace Runtime { systemGraph.reserve(systemGroups.size()); for (const auto& group : systemGroups) { - auto& contexts = systemGraph.emplace_back(); + auto& [systemContexts, strategy] = systemGraph.emplace_back(); const auto& factories = group.GetSystems(); - contexts.reserve(factories.size()); + strategy = group.GetStrategy(); + systemContexts.reserve(factories.size()); for (const auto& factory : group.GetSystems()) { - contexts.emplace_back(factory, nullptr); + systemContexts.emplace_back(factory, nullptr); } } } @@ -1002,22 +957,36 @@ namespace Runtime { tf::Taskflow taskFlow; auto lastBarrier = taskFlow.emplace([]() -> void {}); - for (auto& contexts : systemGraph) { - std::vector tasks; - tasks.reserve(contexts.size()); - - for (auto& context : contexts) { - tasks.emplace_back(taskFlow.emplace([&]() -> void { - inActionFunc(context); - })); - tasks.back().succeed(lastBarrier); - } + for (auto& groupContext : systemGraph) { + if (groupContext.strategy == SystemExecuteStrategy::sequential) { + tf::Task lastTask = lastBarrier; + for (auto& systemContext : groupContext.systems) { + auto task = taskFlow.emplace([&]() -> void { + inActionFunc(systemContext); + }); + task.succeed(lastTask); + lastTask = task; + } + lastBarrier = lastTask; + } else if (groupContext.strategy == SystemExecuteStrategy::concurrent) { + std::vector tasks; + tasks.reserve(groupContext.systems.size()); + + for (auto& systemContext : groupContext.systems) { + tasks.emplace_back(taskFlow.emplace([&]() -> void { + inActionFunc(systemContext); + })); + tasks.back().succeed(lastBarrier); + } - auto barrier = taskFlow.emplace([]() -> void {}); - for (const auto& task : tasks) { - barrier.succeed(task); + auto barrier = taskFlow.emplace([]() -> void {}); + for (const auto& task : tasks) { + barrier.succeed(task); + } + lastBarrier = barrier; + } else { + QuickFail(); } - lastBarrier = barrier; } tf::Executor executor; @@ -1046,7 +1015,7 @@ namespace Runtime { void SystemGraphExecutor::Tick(float inDeltaTimeMs) { pipeline.ParallelPerformAction([&](const SystemPipeline::SystemContext& context) -> void { - context.instance->Execute(inDeltaTimeMs); + context.instance->Tick(inDeltaTimeMs); }); } } // namespace Runtime diff --git a/Engine/Source/Runtime/Src/Engine.cpp b/Engine/Source/Runtime/Src/Engine.cpp index c0a077ee2..1526c1141 100644 --- a/Engine/Source/Runtime/Src/Engine.cpp +++ b/Engine/Source/Runtime/Src/Engine.cpp @@ -19,7 +19,7 @@ namespace Runtime { Assert(renderModule != nullptr); Render::RenderModuleInitParams initParams; - initParams.rhiType = RHI::RHIAbbrStringToRHIType(inParams.rhiType); + initParams.rhiType = RHI::GetRHITypeByAbbrString(inParams.rhiType); renderModule->Initialize(initParams); } @@ -44,13 +44,13 @@ namespace Runtime { return *renderModule; } - void Engine::Tick(float inTimeMs) const + void Engine::Tick(float inTimeSeconds) const { for (auto* world : worlds) { if (!world->Playing()) { continue; } - world->Tick(inTimeMs); + world->Tick(inTimeSeconds); } } @@ -59,7 +59,7 @@ namespace Runtime { return new World(inName); } - Engine* EngineHolder::engine = nullptr; + Common::UniqueRef EngineHolder::engine = nullptr; MinEngine::MinEngine(const EngineInitParams& inParams) : Engine(inParams) @@ -76,7 +76,7 @@ namespace Runtime { void EngineHolder::Load(const std::string& inModuleName, const EngineInitParams& inInitParams) { Assert(engine == nullptr); - auto& gameModule = Core::ModuleManager::Get().GetOrLoadTyped(inModuleName); + auto& gameModule = Core::ModuleManager::Get().GetOrLoadTyped(inModuleName); engine = gameModule.CreateEngine(inInitParams); } diff --git a/Engine/Source/Runtime/Src/World.cpp b/Engine/Source/Runtime/Src/World.cpp index 3c4b0af28..7db9ed507 100644 --- a/Engine/Source/Runtime/Src/World.cpp +++ b/Engine/Source/Runtime/Src/World.cpp @@ -8,6 +8,7 @@ namespace Runtime { World::World(const std::string& inName) : name(inName) + , playStatus(PlayStatus::stopped) { EngineHolder::Get().MountWorld(this); } diff --git a/Engine/Source/Runtime/Test/ECSTest.cpp b/Engine/Source/Runtime/Test/ECSTest.cpp index 43537705c..26cdd767a 100644 --- a/Engine/Source/Runtime/Test/ECSTest.cpp +++ b/Engine/Source/Runtime/Test/ECSTest.cpp @@ -3,6 +3,7 @@ // #include +#include TEST(ECSTest, EntityTest) { @@ -46,12 +47,357 @@ TEST(ECSTest, ComponentStaticTest) ASSERT_EQ(registry.Get(entity1).value, 2); const ECRegistry& constRegistry = registry; + ASSERT_TRUE(constRegistry.Has(entity0)); ASSERT_EQ(constRegistry.Find(entity0)->value, 1); ASSERT_EQ(constRegistry.Find(entity1)->value, 2); ASSERT_EQ(constRegistry.Get(entity0).value, 1); ASSERT_EQ(constRegistry.Get(entity1).value, 2); - // TODO + registry.Remove(entity0); + ASSERT_FALSE(constRegistry.Has(entity0)); + + const auto entity2 = registry.Create(); + registry.Emplace(entity2, 3); + registry.Emplace(entity2, 4.0f); + ASSERT_TRUE(constRegistry.Has(entity2)); + ASSERT_TRUE(constRegistry.Has(entity2)); + ASSERT_EQ(constRegistry.Get(entity2).value, 3); + ASSERT_EQ(constRegistry.Get(entity2).value, 4.0f); + + const auto entity3 = registry.Create(); + registry.Emplace(entity3, 5); + registry.Emplace(entity3, 6.0f); + registry.Remove(entity3); + ASSERT_FALSE(constRegistry.Has(entity3)); + ASSERT_TRUE(constRegistry.Has(entity3)); + ASSERT_EQ(constRegistry.Get(entity3).value, 6.0f); + + std::unordered_set expected = { entity1, entity2 }; + const auto view0 = registry.View(); + ASSERT_EQ(view0.Size(), 2); + view0.Each([&](Entity e, CompA& compA) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + expected = { entity1 }; + const auto view1 = registry.ConstView(Exclude {}); + ASSERT_EQ(view1.Size(), 1); + view1.Each([&](Entity e, const CompA& compA) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + expected = { entity2, entity3 }; + const auto view2 = registry.View(); + ASSERT_EQ(view2.Size(), 2); + for (const auto& [entity, compB] : view2) { + ASSERT_TRUE(expected.contains(entity)); + } + + expected = { entity3 }; + const auto view3 = registry.ConstView(Exclude {}); + ASSERT_EQ(view3.Size(), 1); + for (const auto& [entity, compB] : view3) { + ASSERT_TRUE(expected.contains(entity)); + } +} + +TEST(ECSTest, ComponentDynamicTest) +{ + CompClass compAClass = &Mirror::Class::Get(); + CompClass compBClass = &Mirror::Class::Get(); + + ECRegistry registry; + const ECRegistry& constRegistry = registry; + const auto entity0 = registry.Create(); + const auto entity1 = registry.Create(); + registry.EmplaceDyn(compAClass, entity0, Mirror::ForwardAsArgList(1)); + registry.EmplaceDyn(compAClass, entity1, Mirror::ForwardAsArgList(2)); + ASSERT_TRUE(registry.HasDyn(compAClass, entity0)); + ASSERT_TRUE(constRegistry.HasDyn(compAClass, entity1)); + ASSERT_EQ(registry.GetDyn(compAClass, entity0).As().value, 1); + ASSERT_EQ(constRegistry.GetDyn(compAClass, entity1).As().value, 2); + ASSERT_EQ(registry.FindDyn(compAClass, entity0).As().value, 1); + ASSERT_EQ(constRegistry.FindDyn(compAClass, entity1).As().value, 2); + + std::unordered_set expected = { entity0, entity1 }; + const auto view0 = registry.ConstRuntimeView( + RuntimeFilter() + .IncludeDyn(compAClass)); + ASSERT_EQ(view0.Size(), 2); + view0.Each([&](Entity e, const CompA& compA) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + const auto entity2 = registry.Create(); + registry.EmplaceDyn(compAClass, entity2, Mirror::ForwardAsArgList(3)); + registry.EmplaceDyn(compBClass, entity2, Mirror::ForwardAsArgList(4.0f)); + const auto entity3 = registry.Create(); + registry.EmplaceDyn(compBClass, entity3, Mirror::ForwardAsArgList(5.0f)); + + const auto view1 = registry.RuntimeView( + RuntimeFilter() + .Include()); + expected = { entity0, entity1, entity2 }; + ASSERT_EQ(view1.Size(), 3); + for (const auto& entity : view1) { + ASSERT_TRUE(expected.contains(entity)); + } + + const auto view2 = registry.ConstRuntimeView( + RuntimeFilter() + .Include() + .Exclude()); + expected = { entity0, entity1 }; + ASSERT_EQ(view2.Size(), 2); + view2.Each([&](Entity e, const CompA& compA) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + const auto view3 = registry.RuntimeView( + RuntimeFilter() + .Include()); + expected = { entity2, entity3 }; + ASSERT_EQ(view3.Size(), 2); + view3.Each([&](Entity e, const CompB& compB) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + const auto view4 = registry.ConstRuntimeView( + RuntimeFilter() + .Include() + .Exclude()); + expected = { entity3 }; + ASSERT_EQ(view4.Size(), 1); + view4.Each([&](Entity e, const CompB& compB) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + const auto view5 = constRegistry.ConstRuntimeView( + RuntimeFilter() + .Include() + .Include()); + expected = { entity2 }; + ASSERT_EQ(view5.Size(), 1); + view5.Each([&](Entity e, const CompA& compA, const CompB& compB) -> void { + ASSERT_TRUE(expected.contains(e)); + }); +} + +TEST(ECSTest, GlobalComponentStaticTest) +{ + ECRegistry registry; + registry.GEmplace(1); + ASSERT_TRUE(registry.GHas()); + ASSERT_EQ(registry.GFind()->value, 1); + ASSERT_EQ(registry.GGet().value, 1); + + const ECRegistry& constRegistry = registry; + ASSERT_TRUE(constRegistry.GHas()); + ASSERT_EQ(constRegistry.GFind()->value, 1); + ASSERT_EQ(constRegistry.GGet().value, 1); + + registry.GEmplace(2.0f); + ASSERT_TRUE(registry.GHas()); + ASSERT_TRUE(registry.GHas()); + ASSERT_EQ(registry.GGet().value, 2.0f); + + registry.GRemove(); + ASSERT_TRUE(registry.GHas()); + ASSERT_FALSE(registry.GHas()); +} + +TEST(ECSTest, GlobalComponentDynamicTest) +{ + GCompClass gCompAClass = &Mirror::Class::Get(); + GCompClass gCompBClass = &Mirror::Class::Get(); + + ECRegistry registry; + registry.GEmplaceDyn(gCompAClass, Mirror::ForwardAsArgList(1)); + ASSERT_TRUE(registry.GHasDyn(gCompAClass)); + ASSERT_EQ(registry.GFindDyn(gCompAClass).As().value, 1); + ASSERT_EQ(registry.GGetDyn(gCompAClass).As().value, 1); + + const ECRegistry& constRegistry = registry; + ASSERT_TRUE(constRegistry.GHasDyn(gCompAClass)); + ASSERT_EQ(constRegistry.GFindDyn(gCompAClass).As().value, 1); + ASSERT_EQ(constRegistry.GGetDyn(gCompAClass).As().value, 1); + + registry.GEmplaceDyn(gCompBClass, Mirror::ForwardAsArgList(2.0f)); + ASSERT_TRUE(registry.GHasDyn(gCompAClass)); + ASSERT_TRUE(registry.GHasDyn(gCompBClass)); + ASSERT_EQ(registry.GGetDyn(gCompBClass).As().value, 2.0f); + + registry.GRemoveDyn(gCompBClass); + ASSERT_TRUE(registry.GHasDyn(gCompAClass)); + ASSERT_FALSE(registry.GHasDyn(gCompBClass)); +} + +TEST(ECSTest, ComponentEventStaticTest) +{ + EventCounts count; + ECRegistry registry; + registry.Events().onConstructed.BindLambda([&](ECRegistry&, Entity) -> void { count.onConstructed++; }); + registry.Events().onUpdated.BindLambda([&](ECRegistry&, Entity) -> void { count.onUpdated++; }); + registry.Events().onRemove.BindLambda([&](ECRegistry&, Entity) -> void { count.onRemove++; }); + + const auto entity0 = registry.Create(); + const auto entity1 = registry.Create(); + registry.Emplace(entity0, 1); + ASSERT_EQ(count, EventCounts(1, 0, 0)); + registry.Emplace(entity1, 2); + ASSERT_EQ(count, EventCounts(2, 0, 0)); + + { + const auto updater = registry.Update(entity0); + updater->value = 3; + } + ASSERT_EQ(count, EventCounts(2, 1, 0)); + registry.Update(entity0, [](CompA& compA) -> void { + compA.value = 4; + }); + ASSERT_EQ(count, EventCounts(2, 2, 0)); + registry.Get(entity1).value = 5; + registry.NotifyUpdated(entity1); + ASSERT_EQ(count, EventCounts(2, 3, 0)); + + registry.Remove(entity0); + ASSERT_EQ(count, EventCounts(2, 3, 1)); + registry.Remove(entity1); + ASSERT_EQ(count, EventCounts(2, 3, 2)); +} + +TEST(ECSTest, ComponentEventDynamicTest) +{ + CompClass compAClass = &Mirror::Class::Get(); + EventCounts count; + ECRegistry registry; + registry.EventsDyn(compAClass).onConstructed.BindLambda([&](ECRegistry&, Entity) -> void { count.onConstructed++; }); + registry.EventsDyn(compAClass).onUpdated.BindLambda([&](ECRegistry&, Entity) -> void { count.onUpdated++; }); + registry.EventsDyn(compAClass).onRemove.BindLambda([&](ECRegistry&, Entity) -> void { count.onRemove++; }); + + const auto entity0 = registry.Create(); + const auto entity1 = registry.Create(); + registry.EmplaceDyn(compAClass, entity0, Mirror::ForwardAsArgList(1)); + ASSERT_EQ(count, EventCounts(1, 0, 0)); + registry.EmplaceDyn(compAClass, entity1, Mirror::ForwardAsArgList(2)); + ASSERT_EQ(count, EventCounts(2, 0, 0)); + + { + const auto updater = registry.UpdateDyn(compAClass, entity0); + updater.As().value = 3; + } + ASSERT_EQ(count, EventCounts(2, 1, 0)); + registry.UpdateDyn(compAClass, entity0, [](const Mirror::Any& ref) -> void { + ref.As().value = 4; + }); + ASSERT_EQ(count, EventCounts(2, 2, 0)); + registry.GetDyn(compAClass, entity1).As().value = 5; + registry.NotifyUpdatedDyn(compAClass, entity1); + ASSERT_EQ(count, EventCounts(2, 3, 0)); + + registry.RemoveDyn(compAClass, entity0); + ASSERT_EQ(count, EventCounts(2, 3, 1)); + registry.RemoveDyn(compAClass, entity1); + ASSERT_EQ(count, EventCounts(2, 3, 2)); } -// TODO +TEST(ECSTest, GlobalComponentEventStaticTest) +{ + EventCounts count; + ECRegistry registry; + registry.GEvents().onConstructed.BindLambda([&](ECRegistry&) -> void { count.onConstructed++; }); + registry.GEvents().onUpdated.BindLambda([&](ECRegistry&) -> void { count.onUpdated++; }); + registry.GEvents().onRemove.BindLambda([&](ECRegistry&) -> void { count.onRemove++; }); + + registry.GEmplace(1); + ASSERT_EQ(count, EventCounts(1, 0, 0)); + + { + const auto updater = registry.GUpdate(); + updater->value = 3; + } + ASSERT_EQ(count, EventCounts(1, 1, 0)); + registry.GUpdate([](GCompA& gCompA) -> void { + gCompA.value = 4; + }); + ASSERT_EQ(count, EventCounts(1, 2, 0)); + registry.GGet().value = 5; + registry.GNotifyUpdated(); + ASSERT_EQ(count, EventCounts(1, 3, 0)); + + registry.GRemove(); + ASSERT_EQ(count, EventCounts(1, 3, 1)); +} + +TEST(ECSTest, GlobalComponentEventDynamicTest) +{ + GCompClass gCompAClass = &Mirror::Class::Get(); + EventCounts count; + ECRegistry registry; + registry.GEventsDyn(gCompAClass).onConstructed.BindLambda([&](ECRegistry&) -> void { count.onConstructed++; }); + registry.GEventsDyn(gCompAClass).onUpdated.BindLambda([&](ECRegistry&) -> void { count.onUpdated++; }); + registry.GEventsDyn(gCompAClass).onRemove.BindLambda([&](ECRegistry&) -> void { count.onRemove++; }); + + registry.GEmplaceDyn(gCompAClass, Mirror::ForwardAsArgList(1)); + ASSERT_EQ(count, EventCounts(1, 0, 0)); + + { + const auto updater = registry.GUpdateDyn(gCompAClass); + updater.As().value = 3; + } + ASSERT_EQ(count, EventCounts(1, 1, 0)); + registry.GUpdateDyn(gCompAClass, [](const Mirror::Any& ref) -> void { + ref.As().value = 4; + }); + ASSERT_EQ(count, EventCounts(1, 2, 0)); + registry.GGetDyn(gCompAClass).As().value = 5; + registry.GNotifyUpdatedDyn(gCompAClass); + ASSERT_EQ(count, EventCounts(1, 3, 0)); + + registry.GRemove(); + ASSERT_EQ(count, EventCounts(1, 3, 1)); +} + +TEST(ECSTest, ObserverTest) +{ + ECRegistry registry; + auto observer = registry.Observer(); + observer + .ObConstructed() + .ObUpdatedDyn(&Mirror::Class::Get()); + + const auto entity0 = registry.Create(); + ASSERT_EQ(observer.Size(), 0); + + registry.Emplace(entity0, 1); + ASSERT_EQ(observer.Size(), 1); + std::unordered_set expected = { entity0 }; + observer.Each([&](Entity e) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + const auto entity1 = registry.Create(); + registry.Emplace(entity1, 2.0f); + ASSERT_EQ(observer.Size(), 1); + registry.Update(entity1, [](CompB& compB) -> void { + compB.value = 3.0f; + }); + ASSERT_EQ(observer.Size(), 2); + expected = { entity0, entity1 }; + for (const auto e : expected) { + ASSERT_TRUE(expected.contains(e)); + } +} + +TEST(ECSTest, ECRegistryCopyTest) +{ + ECRegistry registry0; + const auto entity0 = registry0.Create(); + const auto entity1 = registry0.Create(); + registry0.Emplace(entity0, 1); + registry0.Emplace(entity1, 2.0f); + + ECRegistry registry1 = registry0; + ASSERT_EQ(registry1.Get(entity0).value, 1); + ASSERT_EQ(registry1.Get(entity1).value, 2.0f); +} diff --git a/Engine/Source/Runtime/Test/ECSTest.h b/Engine/Source/Runtime/Test/ECSTest.h index 032ae51cf..94dcb58be 100644 --- a/Engine/Source/Runtime/Test/ECSTest.h +++ b/Engine/Source/Runtime/Test/ECSTest.h @@ -18,3 +18,63 @@ struct EClass() CompA { int value; }; + +struct EClass() CompB { + EClassBody(CompB) + + explicit CompB(float inValue) + : value(inValue) + { + } + + float value; +}; + +struct EClass() GCompA { + EClassBody(GCompA) + + explicit GCompA(int inValue) + : value(inValue) + { + } + + int value; +}; + +struct EClass() GCompB { + EClassBody(GCompB) + + explicit GCompB(float inValue) + : value(inValue) + { + } + + float value; +}; + +struct EventCounts { + uint32_t onConstructed; + uint32_t onUpdated; + uint32_t onRemove; + + EventCounts() + : onConstructed(0) + , onUpdated(0) + , onRemove(0) + { + } + + EventCounts(uint32_t inOnConstructed, uint32_t inOnUpdated, uint32_t inOnRemove) + : onConstructed(inOnConstructed) + , onUpdated(inOnUpdated) + , onRemove(inOnRemove) + { + } + + bool operator==(const EventCounts& inRhs) const + { + return onConstructed == inRhs.onConstructed + && onUpdated == inRhs.onUpdated + && onRemove == inRhs.onRemove; + } +}; diff --git a/Engine/Source/Runtime/Test/RuntimeTestModule.cpp b/Engine/Source/Runtime/Test/RuntimeTestModule.cpp index b96708b1f..b87534972 100644 --- a/Engine/Source/Runtime/Test/RuntimeTestModule.cpp +++ b/Engine/Source/Runtime/Test/RuntimeTestModule.cpp @@ -7,7 +7,6 @@ void RuntimeTestModule::OnUnload() { Runtime::EngineHolder::Unload(); - engine.Reset(); } Core::ModuleType RuntimeTestModule::Type() const @@ -17,8 +16,7 @@ Core::ModuleType RuntimeTestModule::Type() const Runtime::Engine* RuntimeTestModule::CreateEngine(const Runtime::EngineInitParams& inParams) { - engine = new Runtime::MinEngine(inParams); - return engine.Get(); + return new Runtime::MinEngine(inParams); } IMPLEMENT_STATIC_MODULE(RuntimeTest, "RuntimeTest", RuntimeTestModule) diff --git a/Engine/Source/Runtime/Test/RuntimeTestModule.h b/Engine/Source/Runtime/Test/RuntimeTestModule.h index 8ab29f481..f47333d26 100644 --- a/Engine/Source/Runtime/Test/RuntimeTestModule.h +++ b/Engine/Source/Runtime/Test/RuntimeTestModule.h @@ -6,12 +6,9 @@ #include -class RuntimeTestModule final : public Runtime::IGameModule { +class RuntimeTestModule final : public Runtime::IEngineModule { public: void OnUnload() override; Core::ModuleType Type() const override; Runtime::Engine* CreateEngine(const Runtime::EngineInitParams& inParams) override; - -private: - Common::UniqueRef engine; }; diff --git a/Engine/Source/Runtime/Test/WorldTest.cpp b/Engine/Source/Runtime/Test/WorldTest.cpp new file mode 100644 index 000000000..a4dba8da1 --- /dev/null +++ b/Engine/Source/Runtime/Test/WorldTest.cpp @@ -0,0 +1,182 @@ +// +// Created by johnk on 2024/12/25. +// + +#include +#include +#include +#include +#include +using namespace Runtime; + +struct WorldTest : testing::Test { + void SetUp() override + { + EngineInitParams engineInitParams; + engineInitParams.rhiType = RHI::GetAbbrStringByType(RHI::RHIType::dummy); + + EngineHolder::Load("RuntimeTest", engineInitParams); + engine = &EngineHolder::Get(); + } + + void TearDown() override + { + EngineHolder::Unload(); + } + + Engine* engine; +}; + +Position::Position() + : x(0.0f) + , y(0.0f) +{ +} + +Position::Position(float inX, float inY) + : x(inX) + , y(inY) +{ +} + +bool Position::operator==(const Position& inRhs) const +{ + return CompareNumber(x, inRhs.x) + && CompareNumber(y, inRhs.y); +} + +Velocity::Velocity() + : x(0.0f) + , y(0.0f) +{ +} + +Velocity::Velocity(float inX, float inY) + : x(inX) + , y(inY) +{ +} + +bool Velocity::operator==(const Velocity& inRhs) const +{ + return CompareNumber(x, inRhs.x) + && CompareNumber(y, inRhs.y); +} + +BasicTest_MotionSystem::BasicTest_MotionSystem(ECRegistry& inRegistry) + : System(inRegistry) +{ + auto entity0 = registry.Create(); + registry.Emplace(entity0, 1.0f, 2.0f); + registry.Emplace(entity0, 0.5f, 1.0f); + + auto entity1 = registry.Create(); + registry.Emplace(entity1, 0.0f, 1.0f); + registry.Emplace(entity1, 1.0f, 0.0f); + + auto& [entities] = registry.GEmplace(); + entities = { + { entity0, Position(1.5f, 3.0f) }, + { entity1, Position(1.0f, 1.0f) } + }; +} + +BasicTest_MotionSystem::~BasicTest_MotionSystem() = default; + +void BasicTest_MotionSystem::Tick(float inDeltaTimeMs) +{ + auto& [entities] = registry.GGet(); + + const auto view = registry.View(); + view.Each([&](Entity entity, Position& position, Velocity& velocity) -> void { + auto& expectPos = entities.at(entity); + position.x += velocity.x; + position.y += velocity.y; + ASSERT_EQ(expectPos, position); + + expectPos.x = position.x + velocity.x; + expectPos.y = position.y + velocity.y; + }); + registry.GNotifyUpdated(); +} + +TEST_F(WorldTest, BasicTest) +{ + SystemGraph systemGraph; + auto& mainGroup = systemGraph.AddGroup("MainGroup", SystemExecuteStrategy::sequential); + mainGroup.EmplaceSystemDyn(&BasicTest_MotionSystem::GetStaticClass()); + + const auto world = engine->CreateWorld(); + world->SetSystemGraph(systemGraph); + world->Play(); + for (auto i = 0; i < 5; i++) { + engine->Tick(0.0167f); + } + world->Stop(); +} + +ConcurrentTest_SystemA::ConcurrentTest_SystemA(Runtime::ECRegistry& inRegistry) + : System(inRegistry) +{ +} + +ConcurrentTest_SystemA::~ConcurrentTest_SystemA() = default; + +void ConcurrentTest_SystemA::Tick(float inDeltaTimeMs) +{ + auto& context = registry.GGet(); + context.a = 1; +} + +ConcurrentTest_SystemB::ConcurrentTest_SystemB(Runtime::ECRegistry& inRegistry) + : System(inRegistry) +{ +} + +ConcurrentTest_SystemB::~ConcurrentTest_SystemB() = default; + +void ConcurrentTest_SystemB::Tick(float inDeltaTimeMs) +{ + auto& context = registry.GGet(); + context.b = 2; +} + +ConcurrentTest_VerifySystem::ConcurrentTest_VerifySystem(Runtime::ECRegistry& inRegistry) + : System(inRegistry) +{ + auto& context = registry.GEmplace(); + context.a = 0; + context.b = 0; + context.sum = 0; + context.tickCount = 0; +} + +ConcurrentTest_VerifySystem::~ConcurrentTest_VerifySystem() = default; + +void ConcurrentTest_VerifySystem::Tick(float inDeltaTimeMs) +{ + auto& context = registry.GGet(); + context.sum = context.sum + context.a + context.b; + context.a = 0; + context.b = 0; + context.tickCount++; + ASSERT_EQ(context.sum, 3 * context.tickCount); +} + +TEST_F(WorldTest, ConcurrentTest) +{ + SystemGraph systemGraph; + auto& ConcurrentGroup = systemGraph.AddGroup("ConcurrentGroup", SystemExecuteStrategy::concurrent); + ConcurrentGroup.EmplaceSystem(); + ConcurrentGroup.EmplaceSystem(); + auto& verifyGroup = systemGraph.AddGroup("VerifyGroup", SystemExecuteStrategy::sequential); + verifyGroup.EmplaceSystem(); + + const auto world = engine->CreateWorld(); + world->SetSystemGraph(systemGraph); + world->Play(); + for (auto i = 0; i < 5; i++) { + engine->Tick(0.0167f); + } + world->Stop(); +} diff --git a/Engine/Source/Runtime/Test/WorldTest.h b/Engine/Source/Runtime/Test/WorldTest.h new file mode 100644 index 000000000..8e3936ed7 --- /dev/null +++ b/Engine/Source/Runtime/Test/WorldTest.h @@ -0,0 +1,86 @@ +// +// Created by johnk on 2024/12/25. +// + +#pragma once + +#include + +#include +#include +#include + +struct EClass() Position { + EClassBody(Position) + + Position(); + Position(float inX, float inY); + + bool operator==(const Position& inRhs) const; + + float x; + float y; +}; + +struct EClass() Velocity { + EClassBody(Velocity) + + Velocity(); + Velocity(float inX, float inY); + + bool operator==(const Velocity& inRhs) const; + + float x; + float y; +}; + +struct EClass() BasicTest_ExpectVerifyResult { + EClassBody(BasicTest_ExpectVerifyResult) + + std::unordered_map entities; +}; + +class EClass() BasicTest_MotionSystem : public Runtime::System { + EClassBody(BasicTest_MotionSystem) + + explicit BasicTest_MotionSystem(Runtime::ECRegistry& inRegistry); + ~BasicTest_MotionSystem() override; + + void Tick(float inDeltaTimeMs) override; +}; + +struct EClass() ConcurrentTest_Context { + EClassBody(ConcurrentTest_Context) + + uint32_t a; + uint32_t b; + uint32_t sum; + uint32_t tickCount; +}; + +struct EClass() ConcurrentTest_SystemA : public Runtime::System { + EClassBody(ConcurrentTest_SystemA) + + explicit ConcurrentTest_SystemA(Runtime::ECRegistry& inRegistry); + ~ConcurrentTest_SystemA() override; + + void Tick(float inDeltaTimeMs) override; +}; + +struct EClass() ConcurrentTest_SystemB : public Runtime::System { + EClassBody(ConcurrentTest_SystemB) + + explicit ConcurrentTest_SystemB(Runtime::ECRegistry& inRegistry); + ~ConcurrentTest_SystemB() override; + + void Tick(float inDeltaTimeMs) override; +}; + +struct EClass() ConcurrentTest_VerifySystem : public Runtime::System { + EClassBody(ConcurrentTest_VerifySystem) + + explicit ConcurrentTest_VerifySystem(Runtime::ECRegistry& inRegistry); + ~ConcurrentTest_VerifySystem() override; + + void Tick(float inDeltaTimeMs) override; +}; diff --git a/Sample/Base/Application.cpp b/Sample/Base/Application.cpp index 4db3f16b0..e9dbec2b3 100644 --- a/Sample/Base/Application.cpp +++ b/Sample/Base/Application.cpp @@ -47,7 +47,7 @@ bool Application::Initialize(int argc, char* argv[]) return false; } - rhiType = RHI::RHIAbbrStringToRHIType(rhiString); + rhiType = RHI::GetRHITypeByAbbrString(rhiString); instance = RHI::Instance::GetByType(rhiType); return true; diff --git a/Script/Windows/ComputeFileSha256.ps1 b/Script/Windows/ComputeFileSha256.ps1 deleted file mode 100644 index e41e0a8b1..000000000 --- a/Script/Windows/ComputeFileSha256.ps1 +++ /dev/null @@ -1,3 +0,0 @@ -param($file) - -Get-FileHash $file -Algorithm SHA256 diff --git a/ThirdParty/CMakeLists.txt b/ThirdParty/CMakeLists.txt index db8564801..e9396450e 100644 --- a/ThirdParty/CMakeLists.txt +++ b/ThirdParty/CMakeLists.txt @@ -8,13 +8,13 @@ Add3rdHeaderOnlyPackage( ) # VulkanSDK -set(VULKAN_SDK_VERSION 1.3.243.0) +set(VULKAN_SDK_VERSION 1.3.296.0) Add3rdBinaryPackage( NAME VulkanSDK VERSION ${VULKAN_SDK_VERSION} HASH - Windows 23ded0e6155a8ea265da84bd62f7a45cc3fc637fb1eeba61a5b9430fa704e4b5 - Darwin a5c63a4f29984540efa00190240d31b59539413cf4783792bd9f53207f4f7d07 + Windows 27b8344a5b1333222d55c9c107914dba1cc9beb788b207e087c27dc7b8762816 + Darwin a792aaad3937a694a4cb853d2fbb3fa7025ba3754bedd52799e687a4c254129c INCLUDE Windows $/Include Darwin $/macOS/include @@ -41,9 +41,23 @@ if (NOT ${CI}) execute_process(COMMAND PowerShell -Command "Start-Process reg -ArgumentList 'add HKEY_LOCAL_MACHINE\\SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers /v ${VALIDATION_LAYER_JSON} /t REG_DWORD /d 0' -Verb RunAs") endif () else (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - # check drivers + # new version of vulkaninfo application use volk to perform dynamic loading, which need libvulkan.dylib in working directory or system, + # so if vulkaninfo print initialized failed, we need copy vulkan dynamic lib to working directory set(PLATFORM_VULKAN_SDK_DIR ${CMAKE_SOURCE_DIR}/ThirdParty/Lib/VulkanSDK-Darwin-${VULKAN_SDK_VERSION}/macOS) - execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) + execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo WORKING_DIRECTORY ${PLATFORM_VULKAN_SDK_DIR}/bin OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) + string(REGEX MATCH "Failed to initialize" MATCH_RESULT ${VULKAN_INFO}) + list(LENGTH MATCH_RESULT MATCH_RESULT_LENGTH) + if (${MATCH_RESULT_LENGTH} GREATER 0) + set(SRC_FILE ${PLATFORM_VULKAN_SDK_DIR}/lib/libvulkan.dylib) + set(DST_FILE ${PLATFORM_VULKAN_SDK_DIR}/bin/libvulkan.dylib) + message("vulkaninfo initialized failed, perform vulkan dynamic library copy: ${SRC_FILE} -> ${DST_FILE}") + file(COPY_FILE ${SRC_FILE} ${DST_FILE} ONLY_IF_DIFFERENT) + else () + message("vulkaninfo test success") + endif () + + # check drivers + execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo WORKING_DIRECTORY ${PLATFORM_VULKAN_SDK_DIR}/bin OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) string(REGEX MATCH "ERROR_INCOMPATIBLE_DRIVER" MATCH_RESULT ${VULKAN_INFO}) list(LENGTH MATCH_RESULT MATCH_RESULT_LENGTH) if (${MATCH_RESULT_LENGTH} GREATER 0) @@ -65,7 +79,7 @@ if (NOT ${CI}) endif () # check layers - execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) + execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo WORKING_DIRECTORY ${PLATFORM_VULKAN_SDK_DIR}/bin OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) string(REGEX MATCH "Layers:\n=======" MATCH_RESULT ${VULKAN_INFO}) list(LENGTH MATCH_RESULT MATCH_RESULT_LENGTH) if (${MATCH_RESULT_LENGTH} GREATER 0) @@ -142,11 +156,11 @@ Add3rdBinaryPackage( NAME llvm-clang ARCH VERSION - Windows-AMD64 17.0.4 - Darwin-arm64 15.0.7 + Windows-AMD64 19.1.6 + Darwin-arm64 19.1.6 HASH - Windows-AMD64 3443a2259d092797521bde0c4b6e402ddeca4beb0abd87274ece91ac44b178ce - Darwin-arm64 99a4884945674163374d99c2220cadbfe20a947b1217193140c6b6638a3b0627 + Windows-AMD64 f68b922c87a99b22c0b53a5cbd55db86bd3870c16c4e9060efaecfb9ce49e726 + Darwin-arm64 08fdf1b6208823acadc23027fda1f12e5171101ec05fa526b545088be31fe19d INCLUDE $/include LINK $/lib LIB @@ -237,32 +251,28 @@ Add3rdHeaderOnlyPackage( ) # Qt6 -Find3rdPackage( +set(QT_VERSION "6.5.2" CACHE STRING "" FORCE) +Setup3rdPackage( NAME Qt - PACKAGE Qt6 - VERSION 6.5.2 + VERSION ${QT_VERSION} HASH Windows e2a573a53b6de88c0ce768868bd5a8258d432ad71c45a407afa55243b051668f Darwin 2fadcb1f07e5f11d4345e7d5631f35f8f4a8033c35901fb20a22c2feb7486e57 PREFIX Windows $/6.5.2/msvc2019_64 Darwin $/6.5.2/macos - COMPONENTS Core Gui Widgets - LIB Qt::Core Qt::Gui Qt::Widgets - RUNTIME_DEP - Windows - $/6.5.2/msvc2019_64/plugins/platforms/qwindows$,d,>.dll->platforms/qwindows$,d,>.dll - $/6.5.2/msvc2019_64/bin/Qt6Core$,d,>.dll - $/6.5.2/msvc2019_64/bin/Qt6Gui$,d,>.dll - $/6.5.2/msvc2019_64/bin/Qt6Widgets$,d,>.dll ) -set(Qt6Core_VERSION_MAJOR 6 CACHE STRING "" FORCE) +if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + set(QT_LIB_PREFIX ${Qt_SOURCE_DIR}/${QT_VERSION}/msvc2019_64 CACHE PATH "" FORCE) +elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set(QT_LIB_PREFIX ${Qt_SOURCE_DIR}/${QT_VERSION}/macos CACHE PATH "" FORCE) +endif () # rapidjson Add3rdHeaderOnlyPackage( NAME rapidjson PLATFORM All - VERSION 1.1.0 - HASH c19c92601374a161b0355ccb73f02b31076c70d4446e5ad53c8b80263a9c900c + VERSION d621dc9 + HASH 696f6ca1ecca9d13170c0a47eda66a3015bcf02a7b4bdd23f574ea302eb4bf3e INCLUDE $/include )