• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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