• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "engine.h"
17 
18 #include <algorithm>
19 #include <chrono>
20 #include <cstring>
21 
22 #include <base/containers/array_view.h>
23 #include <base/containers/atomics.h>
24 #include <base/containers/iterator.h>
25 #include <base/containers/pair.h>
26 #include <base/containers/refcnt_ptr.h>
27 #include <base/containers/string.h>
28 #include <base/containers/string_view.h>
29 #include <base/containers/type_traits.h>
30 #include <base/containers/unique_ptr.h>
31 #include <base/namespace.h>
32 #include <base/util/errors.h>
33 #include <base/util/uid.h>
34 #include <core/ecs/intf_ecs.h>
35 #include <core/engine_info.h>
36 #include <core/implementation_uids.h>
37 #include <core/intf_engine.h>
38 #include <core/io/intf_file_manager.h>
39 #include <core/io/intf_filesystem_api.h>
40 #include <core/log.h>
41 #include <core/namespace.h>
42 #include <core/os/intf_platform.h>
43 #include <core/plugin/intf_class_factory.h>
44 #include <core/plugin/intf_class_register.h>
45 #include <core/plugin/intf_interface.h>
46 #include <core/plugin/intf_plugin.h>
47 #include <core/plugin/intf_plugin_register.h>
48 #include <core/threading/intf_thread_pool.h>
49 
50 #include "image/image_loader_manager.h"
51 #include "os/platform.h"
52 
53 #if (CORE_PERF_ENABLED == 1)
54 #include "perf/performance_data_manager.h"
55 #endif
56 
57 CORE_BEGIN_NAMESPACE()
58 namespace {
59 #if (CORE_EMBEDDED_ASSETS_ENABLED == 1)
60 // Core Rofs Data.
61 extern "C" const uint64_t SIZEOFDATAFORCORE;
62 extern "C" const void* const BINARYDATAFORCORE[];
63 #endif
64 
65 using BASE_NS::array_view;
66 using BASE_NS::make_unique;
67 using BASE_NS::pair;
68 using BASE_NS::string;
69 using BASE_NS::string_view;
70 using BASE_NS::Uid;
71 
72 // This is defined in the CMake generated version.cpp
LogEngineBuildInfo()73 void LogEngineBuildInfo()
74 {
75 #define CORE_TO_STRING_INTERNAL(x) #x
76 #define CORE_TO_STRING(x) CORE_TO_STRING_INTERNAL(x)
77 
78 #ifdef NDEBUG
79     CORE_LOG_I("Core engine version: %s", GetVersion().data());
80 #else
81     CORE_LOG_I("Version: %s (DEBUG)", GetVersion().data());
82 #endif
83 
84     CORE_LOG_I("CORE_VALIDATION_ENABLED=" CORE_TO_STRING(CORE_VALIDATION_ENABLED));
85     CORE_LOG_I("CORE_DEV_ENABLED=" CORE_TO_STRING(CORE_DEV_ENABLED));
86     CORE_LOG_I("CORE_PERF_ENABLED=" CORE_TO_STRING(CORE_PERF_ENABLED));
87 }
88 
GetThreadPoolThreadCount(const uint32_t numberOfHwCores)89 inline constexpr uint32_t GetThreadPoolThreadCount(const uint32_t numberOfHwCores)
90 {
91     // reduce the thread count for default ECS thread pool
92     return numberOfHwCores / 2U;
93 }
94 } // namespace
95 
WARNING_SCOPE_START(W_THIS_USED_BASE_INITIALIZER_LIST)96 WARNING_SCOPE_START(W_THIS_USED_BASE_INITIALIZER_LIST)
97 Engine::Engine(EngineCreateInfo const& createInfo) : platform_(Platform::Create(createInfo.platformCreateInfo))
98 {
99     LogEngineBuildInfo();
100     auto factory = CORE_NS::GetInstance<IFileSystemApi>(UID_FILESYSTEM_API_FACTORY);
101     fileManager_ = factory->CreateFilemanager();
102     fileManager_->RegisterFilesystem("file", factory->CreateStdFileSystem());
103     fileManager_->RegisterFilesystem("memory", factory->CreateMemFileSystem());
104 #if (CORE_EMBEDDED_ASSETS_ENABLED == 1)
105     fileManager_->RegisterFilesystem(
106         "corerofs", factory->CreateROFilesystem(BINARYDATAFORCORE, static_cast<size_t>(SIZEOFDATAFORCORE)));
107 #endif
108 
109     RegisterDefaultPaths();
110 }
WARNING_SCOPE_END()111 WARNING_SCOPE_END()
112 
113 Engine::~Engine()
114 {
115     GetPluginRegister().RemoveListener(*this);
116 
117 #if (CORE_PERF_ENABLED == 1)
118     if (auto perfFactory = CORE_NS::GetInstance<IPerformanceDataManagerFactory>(UID_PERFORMANCE_FACTORY); perfFactory) {
119         for (const auto& perfMan : perfFactory->GetAllCategories()) {
120             CORE_LOG_I("%s PerformanceData for this run:", perfMan->GetCategory().data());
121             static_cast<const PerformanceDataManager&>(*perfMan).DumpToLog();
122         }
123     }
124 #endif
125 
126     UnloadPlugins();
127 
128     fileManager_.reset();
129 }
130 
131 CORE_NS::IEcs* IEcsInstance(IClassFactory&, const IThreadPool::Ptr&, uint64_t ecsId);
132 
CreateEcs()133 IEcs::Ptr Engine::CreateEcs()
134 {
135     // construct a secondary ecs instance.
136     if (auto threadFactory = CORE_NS::GetInstance<ITaskQueueFactory>(UID_TASK_QUEUE_FACTORY); threadFactory) {
137         auto threadPool = threadFactory->CreateThreadPool(GetThreadPoolThreadCount(threadFactory->GetNumberOfCores()));
138         // start from zero
139         const int32_t counter = BASE_NS::AtomicIncrement(&ecsCounter_) - 1;
140         return IEcs::Ptr { IEcsInstance(*this, threadPool, uint64_t(counter)) };
141     }
142 
143     return IEcs::Ptr {};
144 }
145 
CreateEcs(IThreadPool & threadPool)146 IEcs::Ptr Engine::CreateEcs(IThreadPool& threadPool)
147 {
148     // start from zero
149     const int32_t counter = BASE_NS::AtomicIncrement(&ecsCounter_) - 1;
150     return IEcs::Ptr { IEcsInstance(*this, IThreadPool::Ptr { &threadPool }, uint64_t(counter)) };
151 }
152 
Init()153 void Engine::Init()
154 {
155     CORE_LOG_D("Engine init.");
156 
157     imageManager_ = make_unique<ImageLoaderManager>(*fileManager_);
158 
159     LoadPlugins();
160 
161     GetPluginRegister().AddListener(*this);
162 }
163 
RegisterDefaultPaths()164 void Engine::RegisterDefaultPaths()
165 {
166 #if (CORE_EMBEDDED_ASSETS_ENABLED == 1)
167     // Create engine:// protocol that points to embedded engine asset files.
168     CORE_LOG_D("Registered core asset path: 'corerofs://core/'");
169     fileManager_->RegisterPath("engine", "corerofs://core/", false);
170 #endif
171 
172     // Create shaders:// protocol that points to shader files.
173     fileManager_->RegisterPath("shaders", "engine://shaders/", false);
174     // Create shaderstates:// protocol that points to (graphics) shader state files.
175     fileManager_->RegisterPath("shaderstates", "engine://shaderstates/", false);
176     // Create vertexinputdeclarations:// protocol that points to vid files.
177     fileManager_->RegisterPath("vertexinputdeclarations", "engine://vertexinputdeclarations/", false);
178     // Create pipelinelayouts:// protocol that points to vid files.
179     fileManager_->RegisterPath("pipelinelayouts", "engine://pipelinelayouts/", false);
180     // Create renderdataconfigurations:// protocol that points to render byteData configurations.
181     fileManager_->RegisterPath("renderdataconfigurations", "engine://renderdataconfigurations/", false);
182 }
183 
UnloadPlugins()184 void Engine::UnloadPlugins()
185 {
186     for (auto& plugin : plugins_) {
187         if (plugin.second->destroyPlugin) {
188             plugin.second->destroyPlugin(plugin.first);
189         }
190     }
191 }
192 
LoadPlugins()193 void Engine::LoadPlugins()
194 {
195     for (auto info : CORE_NS::GetPluginRegister().GetTypeInfos(IEnginePlugin::UID)) {
196         if (auto enginePlugin = static_cast<const IEnginePlugin*>(info); enginePlugin && enginePlugin->createPlugin) {
197             auto token = enginePlugin->createPlugin(*this);
198             plugins_.push_back({ token, enginePlugin });
199         }
200     }
201 }
202 
TickFrame()203 bool Engine::TickFrame()
204 {
205     return TickFrame({ nullptr, size_t(0) });
206 }
207 
TickFrame(const array_view<IEcs * > & ecsInputs)208 bool Engine::TickFrame(const array_view<IEcs*>& ecsInputs)
209 {
210     using namespace std::chrono;
211     const auto currentTime =
212         static_cast<uint64_t>(duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count());
213 
214     if (firstTime_ == ~0u) {
215         previousFrameTime_ = firstTime_ = currentTime;
216     }
217     deltaTime_ = currentTime - previousFrameTime_;
218     constexpr auto limitHz = duration_cast<microseconds>(duration<float, std::ratio<1, 15u>>(1)).count();
219     if (deltaTime_ > limitHz) {
220         deltaTime_ = limitHz; // clamp the time step to no longer than 15hz.
221     }
222     previousFrameTime_ = currentTime;
223 
224     const uint64_t totalTime = currentTime - firstTime_;
225 
226     bool needRender = false;
227     for (auto& ecs : ecsInputs) {
228         if (TickFrame(*ecs, totalTime, deltaTime_)) {
229             needRender = true;
230         }
231     }
232 
233     return needRender;
234 }
235 
TickFrame(IEcs & ecs,uint64_t totalTime,uint64_t deltaTime)236 bool Engine::TickFrame(IEcs& ecs, uint64_t totalTime, uint64_t deltaTime)
237 {
238     // run garbage collection before updating the systems to ensure only valid entities/ components are available.
239     ecs.ProcessEvents();
240 
241     const bool needRender = ecs.Update(totalTime, deltaTime);
242 
243     // do gc also after the systems have been updated to ensure any deletes done by systems are effective
244     // and client doesn't see stale entities.
245     ecs.ProcessEvents();
246 
247     return needRender;
248 }
249 
GetImageLoaderManager()250 IImageLoaderManager& Engine::GetImageLoaderManager()
251 {
252     CORE_ASSERT_MSG(imageManager_, "Engine not initialized");
253     return *imageManager_;
254 }
255 
GetFileManager()256 IFileManager& Engine::GetFileManager()
257 {
258     CORE_ASSERT_MSG(fileManager_, "Engine not initialized");
259     return *fileManager_;
260 }
261 
GetEngineTime() const262 EngineTime Engine::GetEngineTime() const
263 {
264     return { previousFrameTime_ - firstTime_, deltaTime_ };
265 }
266 
RegisterInterfaceType(const InterfaceTypeInfo & interfaceInfo)267 void Engine::RegisterInterfaceType(const InterfaceTypeInfo& interfaceInfo)
268 {
269     // keep interfaceTypeInfos_ sorted according to UIDs
270     const auto pos = std::upper_bound(interfaceTypeInfos_.cbegin(), interfaceTypeInfos_.cend(), interfaceInfo.uid,
271         [](Uid value, const InterfaceTypeInfo* element) { return value < element->uid; });
272     interfaceTypeInfos_.insert(pos, &interfaceInfo);
273 }
274 
UnregisterInterfaceType(const InterfaceTypeInfo & interfaceInfo)275 void Engine::UnregisterInterfaceType(const InterfaceTypeInfo& interfaceInfo)
276 {
277     if (!interfaceTypeInfos_.empty()) {
278         const auto pos = std::lower_bound(interfaceTypeInfos_.cbegin(), interfaceTypeInfos_.cend(), interfaceInfo.uid,
279             [](const InterfaceTypeInfo* element, Uid value) { return element->uid < value; });
280         if ((pos != interfaceTypeInfos_.cend()) && (*pos)->uid == interfaceInfo.uid) {
281             interfaceTypeInfos_.erase(pos);
282         }
283     }
284 }
285 
GetInterfaceMetadata() const286 array_view<const InterfaceTypeInfo* const> Engine::GetInterfaceMetadata() const
287 {
288     return interfaceTypeInfos_;
289 }
290 
GetInterfaceMetadata(const Uid & uid) const291 const InterfaceTypeInfo& Engine::GetInterfaceMetadata(const Uid& uid) const
292 {
293     static constexpr InterfaceTypeInfo invalidType {};
294 
295     if (!interfaceTypeInfos_.empty()) {
296         const auto pos = std::lower_bound(interfaceTypeInfos_.cbegin(), interfaceTypeInfos_.cend(), uid,
297             [](const InterfaceTypeInfo* element, Uid value) { return element->uid < value; });
298         if ((pos != interfaceTypeInfos_.cend()) && (*pos)->uid == uid) {
299             return *(*pos);
300         }
301     }
302     return invalidType;
303 }
304 
GetInstance(const Uid & uid) const305 IInterface* Engine::GetInstance(const Uid& uid) const
306 {
307     const auto& data = GetInterfaceMetadata(uid);
308     if (data.getInterface) {
309         return data.getInterface(const_cast<Engine&>(*this), data.token);
310     }
311     return nullptr;
312 }
313 
CreateInstance(const Uid & uid)314 IInterface::Ptr Engine::CreateInstance(const Uid& uid)
315 {
316     const auto& data = GetInterfaceMetadata(uid);
317     if (data.createInterface) {
318         return IInterface::Ptr { data.createInterface(*this, data.token) };
319     }
320     return {};
321 }
322 
GetInterface(const BASE_NS::Uid & uid) const323 const IInterface* Engine::GetInterface(const BASE_NS::Uid& uid) const
324 {
325     if (auto ret = IInterfaceHelper::GetInterface(uid)) {
326         return ret;
327     }
328     return nullptr;
329 }
330 
GetInterface(const BASE_NS::Uid & uid)331 IInterface* Engine::GetInterface(const BASE_NS::Uid& uid)
332 {
333     if (auto ret = IInterfaceHelper::GetInterface(uid)) {
334         return ret;
335     }
336     return nullptr;
337 }
338 
OnTypeInfoEvent(EventType type,array_view<const ITypeInfo * const> typeInfos)339 void Engine::OnTypeInfoEvent(EventType type, array_view<const ITypeInfo* const> typeInfos)
340 {
341     if (type == EventType::ADDED) {
342         for (const auto* info : typeInfos) {
343             if (info && info->typeUid == IEnginePlugin::UID && static_cast<const IEnginePlugin*>(info)->createPlugin) {
344                 auto enginePlugin = static_cast<const IEnginePlugin*>(info);
345                 if (std::none_of(plugins_.begin(), plugins_.end(),
346                                  [enginePlugin](const pair<PluginToken, const IEnginePlugin *> &pluginData) {
347                                      return pluginData.second == enginePlugin;
348                                  })) {
349                     auto token = enginePlugin->createPlugin(*this);
350                     plugins_.push_back({ token, enginePlugin });
351                 }
352             }
353         }
354     } else if (type == EventType::REMOVED) {
355         for (const auto* info : typeInfos) {
356             if (!info || info->typeUid != IEnginePlugin::UID) {
357                 continue;
358             }
359             auto enginePlugin = static_cast<const IEnginePlugin*>(info);
360             if (auto pos = std::find_if(plugins_.cbegin(), plugins_.cend(),
361                                         [enginePlugin](const pair<PluginToken, const IEnginePlugin *> &pluginData) {
362                                             return pluginData.second == enginePlugin;
363                                         });
364                 pos != plugins_.cend()) {
365                 if (enginePlugin->destroyPlugin) {
366                     enginePlugin->destroyPlugin(pos->first);
367                 }
368                 plugins_.erase(pos);
369             }
370         }
371     }
372 }
373 
GetVersion()374 string_view Engine::GetVersion()
375 {
376     return CORE_NS::GetVersion();
377 }
378 
IsDebugBuild()379 bool Engine::IsDebugBuild()
380 {
381     return CORE_NS::IsDebugBuild();
382 }
383 
CreateEngine(EngineCreateInfo const & createInfo)384 IEngine::Ptr CreateEngine(EngineCreateInfo const& createInfo)
385 {
386     auto engine = new Engine(createInfo);
387     return IEngine::Ptr { engine };
388 }
389 
GetPlatform() const390 const IPlatform& Engine::GetPlatform() const
391 {
392     return *platform_;
393 }
394 CORE_END_NAMESPACE()
395