1 /*
2 * Copyright (c) 2021 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 "scene_init.h"
17 #include "scene_adapter/scene_adapter.h"
18
19 #include "3d_widget_adapter_log.h"
20
21 #include "scene_adapter/scene_adapter.h"
22
23 #include <dlfcn.h>
24 #include <memory>
25 #include <string_view>
26
27 #include "napi/native_api.h"
28 #include "napi/native_node_api.h"
29
30 #include <base/containers/array_view.h>
31
32 #include <core/intf_engine.h>
33 #include <core/ecs/intf_system_graph_loader.h>
34 #include <core/engine_info.h>
35 #include <core/implementation_uids.h>
36 #include <core/io/intf_file_manager.h>
37 #include <core/namespace.h>
38 #include <core/os/intf_platform.h>
39 #include <core/plugin/intf_plugin_register.h>
40 #include <core/property/intf_property_handle.h>
41 #include <3d/implementation_uids.h>
42 #include <3d/intf_graphics_context.h>
43
44 #include <meta/interface/intf_meta_object_lib.h>
45 #include <meta/interface/intf_task_queue_registry.h>
46 #include <meta/interface/intf_task_queue.h>
47 #include <meta/interface/intf_object.h>
48 #include <meta/interface/intf_object_registry.h>
49 #include <meta/interface/intf_task_queue.h>
50 #include <meta/base/shared_ptr.h>
51 #include <meta/base/interface_macros.h>
52 #include <meta/api/make_callback.h>
53 #include <meta/ext/object.h>
54
55 #include <scene_plugin/namespace.h>
56 #include <scene_plugin/interface/intf_scene.h>
57 #include <scene_plugin/interface/intf_ecs_scene.h>
58 #include <scene_plugin/interface/intf_mesh.h>
59 #include <scene_plugin/interface/intf_material.h>
60 #include <scene_plugin/api/scene_uid.h>
61
62 #include "napi_base_context.h"
63
64 #include <render/implementation_uids.h>
65 #include <render/gles/intf_device_gles.h>
66 #include <render/intf_renderer.h>
67 #include <render/intf_render_context.h>
68
69 #include "3d_widget_adapter_log.h"
70 #include "widget_trace.h"
71 #include "ohos/texture_layer.h"
72
73 CORE_BEGIN_NAMESPACE()
74 /** Get plugin register */
75 IPluginRegister &(*GetPluginRegister)() = nullptr;
76
77 /** Setup the plugin register */
78 void (*CreatePluginRegistry)(const struct PlatformCreateInfo &platformCreateInfo) = nullptr;
79
80 /** Get whether engine is build in debug mode */
81 bool (*IsDebugBuild)() = nullptr;
82
83 /** Get version */
84 BASE_NS::string_view (*GetVersion)() = nullptr;
85 CORE_END_NAMESPACE()
86
87 namespace OHOS::FUZZ {
88
89 // class SceneInit : public ISceneInit {
90 class SceneInit : public ISceneInit {
91 public:
92 SceneInit();
93
94 bool LoadPluginsAndInit() override;
95
96 std::shared_ptr<Render3D::TextureLayer> CreateTextureLayer() override;
97
98 void OnWindowChange(const Render3D::WindowChangeInfo &windowChangeInfo) override;
99
100 void RenderFrame(bool needsSyncPaint = false) override;
101
102 EngineInstance& GetEngineInstance() override;
103
104 void Deinit() override;
105
NeedsRepaint()106 bool NeedsRepaint() override
107 {
108 return false;
109 }
110
111 static void ShutdownPluginRegistry();
112 static void DeinitRenderThread();
113
114 ~SceneInit();
115
116 private:
117 static bool LoadEngineLib();
118 bool LoadPlugins(const CORE_NS::PlatformCreateInfo &platformCreateInfo);
119 bool InitEngine(CORE_NS::PlatformCreateInfo platformCreateInfo);
120 void AttachSwapchain(META_NS::IObject::Ptr camera, RENDER_NS::RenderHandleReference swapchain);
121 void RenderFunction();
122 void CreateRenderFunction();
123 std::shared_ptr<ISceneAdapter> scene_;
124 };
125
GetHapInfo()126 Render3D::HapInfo GetHapInfo()
127 {
128 return {};
129 }
130
131 using IntfPtr = META_NS::SharedPtrIInterface;
132 using IntfWeakPtr = META_NS::WeakPtrIInterface;
133
134 static EngineInstance engineInstance_;
135 static std::mutex mute;
136 static Render3D::HapInfo hapInfo_;
137 META_NS::ITaskQueue::Ptr engineThread;
138 META_NS::ITaskQueue::Ptr ioThread;
139 META_NS::ITaskQueue::Ptr releaseThread;
140 META_NS::ITaskQueue::Token renderTask{};
141
GetEngineInstance()142 EngineInstance& SceneInit::GetEngineInstance() {
143 return engineInstance_;
144 }
145
LockCompositor()146 void LockCompositor()
147 {
148 mute.lock();
149 }
150
UnlockCompositor()151 void UnlockCompositor()
152 {
153 mute.unlock();
154 }
155
156 static constexpr BASE_NS::Uid ENGINE_THREAD{"2070e705-d061-40e4-bfb7-90fad2c280af"};
157 static constexpr BASE_NS::Uid APP_THREAD{"b2e8cef3-453a-4651-b564-5190f8b5190d"};
158 static constexpr BASE_NS::Uid IO_QUEUE{"be88e9a0-9cd8-45ab-be48-937953dc258f"};
159 static constexpr BASE_NS::Uid JS_RELEASE_THREAD{"3784fa96-b25b-4e9c-bbf1-e897d36f73af"};
160
161 template <typename T>
LoadFunc(T & fn,const char * fName,void * handle)162 bool LoadFunc(T &fn, const char *fName, void *handle)
163 {
164 fn = reinterpret_cast<T>(dlsym(handle, fName));
165 if (fn == nullptr) {
166 WIDGET_LOGE("%s open %s", __func__, dlerror());
167 return false;
168 }
169 return true;
170 }
171
SceneInit()172 SceneInit::SceneInit()
173 {
174 WIDGET_LOGD("scene adapter Impl create");
175 }
176
LoadEngineLib()177 bool SceneInit::LoadEngineLib()
178 {
179 if (engineInstance_.libHandle_ != nullptr) {
180 WIDGET_LOGD("%s, already loaded", __func__);
181 return true;
182 }
183
184 #define TO_STRING(name) #name
185 #define LIB_NAME(name) TO_STRING(name)
186 constexpr std::string_view lib{LIB_NAME(LIB_ENGINE_CORE) ".so"};
187 engineInstance_.libHandle_ = dlopen(lib.data(), RTLD_LAZY);
188
189 if (engineInstance_.libHandle_ == nullptr) {
190 WIDGET_LOGE("%s, open lib fail %s", __func__, dlerror());
191 }
192 #undef TO_STRING
193 #undef LIB_NAME
194
195 #define LOAD_FUNC(fn, name) LoadFunc<decltype(fn)>(fn, name, engineInstance_.libHandle_)
196 if (!(LOAD_FUNC(CORE_NS::CreatePluginRegistry, "_ZN4Core20CreatePluginRegistryERKNS_18PlatformCreateInfoE") &&
197 LOAD_FUNC(CORE_NS::GetPluginRegister, "_ZN4Core17GetPluginRegisterEv") &&
198 LOAD_FUNC(CORE_NS::IsDebugBuild, "_ZN4Core12IsDebugBuildEv") &&
199 LOAD_FUNC(CORE_NS::GetVersion, "_ZN4Core13GetVersionRevEv"))) {
200 return false;
201 }
202 #undef LOAD_FUNC
203
204 return true;
205 }
206
LoadPlugins(const CORE_NS::PlatformCreateInfo & platformCreateInfo)207 bool SceneInit::LoadPlugins(const CORE_NS::PlatformCreateInfo &platformCreateInfo)
208 {
209 if (engineInstance_.libsLoaded_) {
210 return true;
211 }
212 if (!LoadEngineLib()) {
213 return false;
214 }
215 engineInstance_.libsLoaded_ = true;
216 WIDGET_LOGD("load engine success!");
217
218 return true;
219 }
220
InitEngine(CORE_NS::PlatformCreateInfo platformCreateInfo)221 bool SceneInit::InitEngine(CORE_NS::PlatformCreateInfo platformCreateInfo)
222 {
223 #ifdef SCENE_META_FUZZ
224 auto &tr = META_NS::GetTaskQueueRegistry();
225 auto &obr = META_NS::GetObjectRegistry();
226
227 engineThread = tr.GetTaskQueue(ENGINE_THREAD);
228 if (!engineThread) {
229 engineThread = obr.Create<META_NS::ITaskQueue>(META_NS::ClassId::ThreadedTaskQueue);
230 tr.RegisterTaskQueue(engineThread, ENGINE_THREAD);
231 }
232 ioThread = tr.GetTaskQueue(IO_QUEUE);
233 if (!ioThread) {
234 ioThread = obr.Create<META_NS::ITaskQueue>(META_NS::ClassId::ThreadedTaskQueue);
235 tr.RegisterTaskQueue(ioThread, IO_QUEUE);
236 }
237 releaseThread = tr.GetTaskQueue(JS_RELEASE_THREAD);
238 if (!releaseThread) {
239 auto &obr = META_NS::GetObjectRegistry();
240 releaseThread = obr.Create<META_NS::ITaskQueue>(META_NS::ClassId::ThreadedTaskQueue);
241 tr.RegisterTaskQueue(releaseThread, JS_RELEASE_THREAD);
242 }
243
244 auto engineInit = META_NS::MakeCallback<META_NS::ITaskQueueTask>([platformCreateInfo]() {
245 #endif
246 // Initialize lumeengine/render etc
247 #ifdef SCENE_META_FUZZ
248 const BASE_NS::Uid DefaultPluginList[] { SCENE_NS::UID_SCENE_PLUGIN };
249 #else
250 const BASE_NS::Uid DefaultPluginList[] { RENDER_NS::UID_RENDER_PLUGIN, CORE3D_NS::UID_3D_PLUGIN };
251 #endif
252 CORE_NS::CreatePluginRegistry(platformCreateInfo);
253 if (!CORE_NS::GetPluginRegister().LoadPlugins(DefaultPluginList)) {
254 WIDGET_LOGE("fail to load scene widget plugin");
255 return false;
256 }
257 WIDGET_LOGI("load plugin success");
258 CORE_NS::EngineCreateInfo engineCreateInfo{platformCreateInfo, {}, {}};
259 if (auto factory = CORE_NS::GetInstance<CORE_NS::IEngineFactory>(CORE_NS::UID_ENGINE_FACTORY)) {
260 engineInstance_.engine_.reset(factory->Create(engineCreateInfo).get());
261 }
262
263 if (!engineInstance_.engine_) {
264 WIDGET_LOGE("get engine fail");
265 return false;
266 }
267 engineInstance_.engine_->Init();
268
269 engineInstance_.renderContext_.reset(
270 CORE_NS::CreateInstance<RENDER_NS::IRenderContext>(*engineInstance_.engine_, RENDER_NS::UID_RENDER_CONTEXT)
271 .get());
272 if (!engineInstance_.renderContext_) {
273 WIDGET_LOGE("get render context fail");
274 return false;
275 }
276
277 RENDER_NS::RenderCreateInfo renderCreateInfo;
278 RENDER_NS::BackendExtraGLES glExtra;
279 Render::DeviceCreateInfo deviceCreateInfo;
280 // this context needs to be "not busy" (not selected current in any thread) for creation to succeed.
281 // vulkan currently has no bloom
282 std::string backendProp =
283 "gles"; // Render3D::RenderConfig::GetInstance().renderBackend_ == "force_vulkan" ? "vulkan" : "gles";
284 if (backendProp == "vulkan") {
285 } else {
286 glExtra.depthBits = 24; // 24 :bits size
287 glExtra.sharedContext = EGL_NO_CONTEXT;
288 deviceCreateInfo.backendType = RENDER_NS::DeviceBackendType::OPENGLES;
289 deviceCreateInfo.backendConfiguration = &glExtra;
290 renderCreateInfo.applicationInfo = {};
291 renderCreateInfo.deviceCreateInfo = deviceCreateInfo;
292 }
293
294 auto rrc = engineInstance_.renderContext_->Init(renderCreateInfo);
295 if (rrc != RENDER_NS::RenderResultCode::RENDER_SUCCESS) {
296 WIDGET_LOGE("Failed to create render context");
297 return false;
298 }
299
300 engineInstance_.graphicsContext_.reset(CORE_NS::CreateInstance<CORE3D_NS::IGraphicsContext>(
301 *engineInstance_.renderContext_->GetInterface<CORE_NS::IClassFactory>(), CORE3D_NS::UID_GRAPHICS_CONTEXT)
302 .get());
303 if (!engineInstance_.graphicsContext_) {
304 WIDGET_LOGE("create 3D context fail");
305 return false;
306 }
307 engineInstance_.graphicsContext_->Init();
308
309 WIDGET_LOGD("regester shader path");
310 static constexpr const RENDER_NS::IShaderManager::ShaderFilePathDesc desc{"shaders://"};
311 engineInstance_.engine_->GetFileManager().RegisterPath("shaders", "OhosRawFile://shaders", false);
312 engineInstance_.renderContext_->GetDevice().GetShaderManager().LoadShaderFiles(desc);
313
314 engineInstance_.engine_->GetFileManager().RegisterPath("appshaders", "OhosRawFile://shaders", false);
315 static constexpr const RENDER_NS::IShaderManager::ShaderFilePathDesc desc1{"appshaders://"};
316 engineInstance_.renderContext_->GetDevice().GetShaderManager().LoadShaderFiles(desc1);
317
318 WIDGET_LOGI("init engine success");
319
320 #ifdef SCENE_META_FUZZ
321 auto &obr = META_NS::GetObjectRegistry();
322 // scene/meta
323 // Save the stuff to the default object context.
324 auto engineThread = META_NS::GetTaskQueueRegistry().GetTaskQueue(ENGINE_THREAD);
325 // // this is the javascript thread...
326 auto appThread = engineThread;
327 auto doc = interface_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
328 if (doc == nullptr) {
329 WIDGET_LOGE("nullptr from interface_cast");
330 return false;
331 }
332
333 auto flags = META_NS::ObjectFlagBits::INTERNAL | META_NS::ObjectFlagBits::NATIVE;
334
335 doc->AddProperty(META_NS::ConstructProperty<IntfPtr>("RenderContext", nullptr, flags));
336 doc->AddProperty(META_NS::ConstructProperty<IntfPtr>("EngineQueue", nullptr, flags));
337 doc->AddProperty(META_NS::ConstructProperty<IntfPtr>("AppQueue", nullptr, flags));
338 doc->AddProperty(META_NS::ConstructArrayProperty<IntfWeakPtr>("Scenes", {}, flags));
339
340 doc->GetPropertyByName<META_NS::SharedPtrIInterface>("EngineQueue")->SetValue(engineThread);
341 doc->GetPropertyByName<META_NS::SharedPtrIInterface>("AppQueue")->SetValue(appThread);
342 doc->GetPropertyByName<META_NS::SharedPtrIInterface>("RenderContext")->SetValue(engineInstance_.renderContext_);
343
344 return false;
345 });
346
347 engineThread->AddTask(engineInit);
348 #endif
349 return true;
350 }
351
Deinit()352 void SceneInit::Deinit()
353 {
354 engineInstance_.graphicsContext_.reset();
355
356 engineInstance_.renderContext_->GetRenderer().RenderFrame({});
357
358 engineInstance_.renderContext_->GetDevice().WaitForIdle();
359
360 engineInstance_.renderContext_.reset();
361
362 #if SCENE_META_FUZZ
363 const BASE_NS::Uid DefaultPluginList[]{SCENE_NS::UID_SCENE_PLUGIN};
364 #else
365 const BASE_NS::Uid DefaultPluginList[]{RENDER_NS::UID_RENDER_PLUGIN, CORE3D_NS::UID_3D_PLUGIN};
366 #endif
367 CORE_NS::GetPluginRegister().UnloadPlugins(DefaultPluginList);
368 }
369
~SceneInit()370 SceneInit::~SceneInit()
371 {
372 Deinit();
373 }
374
DeinitRenderThread()375 void SceneInit::DeinitRenderThread()
376 {
377 #if SCENE_META_FUZZ
378 if (renderTask) {
379 engineThread->CancelTask(renderTask);
380 renderTask = nullptr;
381 }
382 auto engine_deinit = META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>([]() {
383 // destroy all swapchains
384 auto &obr = META_NS::GetObjectRegistry();
385 auto doc = interface_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
386 if (doc == nullptr) {
387 WIDGET_LOGE("nullptr from interface_cast");
388 return META_NS::IAny::Ptr{};
389 }
390 // this is somewhat uncool
391 {
392 auto p3 = doc->GetPropertyByName<IntfPtr>("RenderContext");
393 doc->RemoveProperty(p3);
394 auto p2 = doc->GetPropertyByName<IntfPtr>("AppQueue");
395 doc->RemoveProperty(p2);
396 auto p1 = doc->GetPropertyByName<IntfPtr>("EngineQueue");
397 doc->RemoveProperty(p1);
398 }
399
400 doc->GetArrayPropertyByName<IntfWeakPtr>("Scenes")->Reset();
401
402 return META_NS::IAny::Ptr{};
403 });
404 auto dummy = META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>([]() { return META_NS::IAny::Ptr{}; });
405 auto &tr = META_NS::GetTaskQueueRegistry();
406 if (releaseThread) {
407 releaseThread->AddWaitableTask(dummy)->Wait();
408 tr.UnregisterTaskQueue(JS_RELEASE_THREAD);
409 releaseThread.reset();
410 }
411
412 if (ioThread) {
413 ioThread->AddWaitableTask(dummy)->Wait();
414 tr.UnregisterTaskQueue(IO_QUEUE);
415 ioThread.reset();
416 }
417
418 if (engineThread) {
419 engineThread->AddWaitableTask(engine_deinit)->Wait();
420
421 tr.UnregisterTaskQueue(ENGINE_THREAD);
422 engineThread.reset();
423 }
424 #endif
425 CORE_LOG_E("unload E");
426 #if SCENE_META_FUZZ
427 const BASE_NS::Uid DefaultPluginList[]{SCENE_NS::UID_SCENE_PLUGIN};
428 #else
429 const BASE_NS::Uid DefaultPluginList[]{RENDER_NS::UID_RENDER_PLUGIN, CORE3D_NS::UID_3D_PLUGIN};
430 #endif
431 CORE_NS::GetPluginRegister().UnloadPlugins(DefaultPluginList);
432 CORE_LOG_E("unload X");
433 engineInstance_.renderContext_.reset();
434 engineInstance_.engine_.reset();
435 }
436
CreateTextureLayer()437 std::shared_ptr<Render3D::TextureLayer> SceneInit::CreateTextureLayer()
438 {
439 return {};
440 }
441
LoadPluginsAndInit()442 bool SceneInit::LoadPluginsAndInit()
443 {
444 LockCompositor(); // an APP_FREEZE here, so add lock just in case, but suspect others' error
445 WIDGET_LOGI("scene adapter loadPlugins");
446
447 if (hapInfo_.hapPath_ == "") {
448 hapInfo_ = GetHapInfo();
449 }
450
451 #define TO_STRING(name) #name
452 #define PLATFORM_PATH_NAME(name) TO_STRING(name)
453 CORE_NS::PlatformCreateInfo platformCreateInfo {
454 PLATFORM_PATH_NAME(PLATFORM_CORE_ROOT_PATH),
455 PLATFORM_PATH_NAME(PLATFORM_APP_ROOT_PATH),
456 PLATFORM_PATH_NAME(PLATFORM_APP_PLUGIN_PATH),
457 hapInfo_.hapPath_.c_str(),
458 hapInfo_.bundleName_.c_str(),
459 hapInfo_.moduleName_.c_str()
460 };
461 #undef TO_STRING
462 #undef PLATFORM_PATH_NAME
463 if (!LoadPlugins(platformCreateInfo)) {
464 WIDGET_LOGE("LoadPlugins failed");
465 UnlockCompositor();
466 return false;
467 }
468
469 if (!InitEngine(platformCreateInfo)) {
470 WIDGET_LOGE("InitEngine failed");
471 UnlockCompositor();
472 return false;
473 }
474
475 CreateRenderFunction();
476 UnlockCompositor();
477 return true;
478 }
479
OnWindowChange(const Render3D::WindowChangeInfo & windowChangeInfo)480 void SceneInit::OnWindowChange(const Render3D::WindowChangeInfo &windowChangeInfo)
481 {}
482
CreateRenderFunction()483 void SceneInit::CreateRenderFunction()
484 {}
485
ShutdownPluginRegistry()486 void SceneInit::ShutdownPluginRegistry()
487 {
488 if (engineInstance_.libHandle_ == nullptr) {
489 return ;
490 }
491
492 CORE_NS::GetPluginRegister = nullptr;
493 CORE_NS::CreatePluginRegistry = nullptr;
494 CORE_NS::IsDebugBuild = nullptr;
495 CORE_NS::GetVersion = nullptr;
496 }
497
RenderFunction()498 void SceneInit::RenderFunction()
499 {}
500
RenderFrame(bool needsSyncPaint)501 void SceneInit::RenderFrame(bool needsSyncPaint)
502 {}
503
CreateFuzzScene()504 std::shared_ptr<ISceneInit> CreateFuzzScene()
505 {
506 return std::make_shared<SceneInit>();
507 }
508 } // namespace OHOS::FUZZ