1 /*
2 * Copyright (c) 2024 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_adapter/scene_adapter.h"
17
18 #include <dlfcn.h>
19 #include <memory>
20 #include <string_view>
21
22 #include "napi/native_api.h"
23 #include "napi/native_node_api.h"
24
25 #include <base/containers/array_view.h>
26
27 #include <core/intf_engine.h>
28 #include <core/ecs/intf_system_graph_loader.h>
29 #include <core/engine_info.h>
30 #include <core/image/intf_image_loader_manager.h>
31 #include <core/implementation_uids.h>
32 #include <core/io/intf_file_manager.h>
33 #include <core/namespace.h>
34 #include <core/os/intf_platform.h>
35 #include <core/plugin/intf_plugin_register.h>
36 #include <core/property/intf_property_handle.h>
37
38 #include <jpg/implementation_uids.h>
39
40 #include <meta/interface/intf_meta_object_lib.h>
41 #include <meta/interface/intf_task_queue_registry.h>
42 #include <meta/interface/intf_task_queue.h>
43 #include <meta/interface/intf_object.h>
44 #include <meta/interface/intf_object_registry.h>
45 #include <meta/interface/intf_task_queue.h>
46 #include <meta/base/shared_ptr.h>
47 #include <meta/base/interface_macros.h>
48 #include <meta/api/make_callback.h>
49 #include <meta/ext/object.h>
50
51 #include <png/implementation_uids.h>
52 #include <scene/base/namespace.h>
53 #include <scene/interface/intf_scene.h>
54 #include <3d/ecs/components/environment_component.h>
55 #include <3d/ecs/components/render_handle_component.h>
56 #include <3d/ecs/components/uri_component.h>
57 #include <scene/ext/intf_internal_scene.h>
58 #include <scene/interface/intf_mesh.h>
59 #include <scene/interface/intf_material.h>
60 #include <scene/ext/intf_render_resource.h>
61 #include <scene/interface/intf_camera.h>
62 #include <scene/ext/intf_internal_scene.h>
63 #include <scene/ext/intf_ecs_context.h>
64
65 #include <scene/ext/intf_ecs_object_access.h>
66 #include <text_3d/implementation_uids.h>
67 #include "ability.h"
68
69 #include "data_ability_helper.h"
70
71 #include "napi_base_context.h"
72
73 #include <render/implementation_uids.h>
74 #include <render/gles/intf_device_gles.h>
75 #include <render/intf_renderer.h>
76 #include <render/intf_render_context.h>
77 #include <render/util/intf_render_util.h>
78 #include <render/vulkan/intf_device_vk.h>
79
80 #include "3d_widget_adapter_log.h"
81 #include "widget_trace.h"
82 #include "ohos/texture_layer.h"
83 #include "lume_render_config.h"
84
85 #include <cam_preview/namespace.h>
86 #include <cam_preview/implementation_uids.h>
87
88 // surface buffer
89 #include <native_buffer.h>
90 #include <surface_buffer.h>
91 #include <securec.h>
92
93 namespace OHOS::Render3D {
94 #define RETURN_IF_NULL(ptr) \
95 do { \
96 if (!(ptr)) { \
97 WIDGET_LOGE("%s is null in %s", #ptr, __func__); \
98 return; \
99 } \
100 } while (0) \
101
102 #define RETURN_FALSE_IF_NULL(ptr) \
103 do { \
104 if (!(ptr)) { \
105 WIDGET_LOGE("%s is null in %s", #ptr, __func__); \
106 return false; \
107 } \
108 } while (0) \
109
110
GetHapInfo()111 HapInfo GetHapInfo()
112 {
113 WIDGET_SCOPED_TRACE("SceneAdapter::GetHapInfo");
114 std::shared_ptr<AbilityRuntime::ApplicationContext> context =
115 AbilityRuntime::ApplicationContext::GetApplicationContext();
116 if (!context) {
117 WIDGET_LOGE("Failed to get application context.");
118 return {};
119 }
120 auto resourceManager = context->GetResourceManager();
121 if (!resourceManager) {
122 WIDGET_LOGE("Failed to get resource manager.");
123 return {};
124 }
125 HapInfo hapInfo;
126 hapInfo.bundleName_ = resourceManager->bundleInfo.first;
127 hapInfo.moduleName_ = resourceManager->bundleInfo.second;
128 hapInfo.resourceManager_ = context->CreateModuleResourceManager(hapInfo.bundleName_, hapInfo.moduleName_);
129 // hapPath
130 std::string hapPath = context->GetBundleCodeDir();
131 hapInfo.hapPath_ = hapPath + "/" + hapInfo.moduleName_ + ".hap";
132 WIDGET_LOGD("bundle %s, module %s, hapPath %s",
133 hapInfo.bundleName_.c_str(),
134 hapInfo.moduleName_.c_str(),
135 hapInfo.hapPath_.c_str());
136
137 return hapInfo;
138 }
139
140 using IntfPtr = META_NS::SharedPtrIInterface;
141 using IntfWeakPtr = META_NS::WeakPtrIInterface;
142
143 struct EngineInstance {
144 void *libHandle_ = nullptr;
145 BASE_NS::shared_ptr<RENDER_NS::IRenderContext> renderContext_;
146 BASE_NS::shared_ptr<CORE_NS::IEngine> engine_;
147 };
148
149 static EngineInstance engineInstance_;
150 static std::mutex mute;
151 static HapInfo hapInfo_;
152 META_NS::ITaskQueue::Ptr engineThread;
153 META_NS::ITaskQueue::Ptr ioThread;
154 META_NS::ITaskQueue::Ptr releaseThread;
155 META_NS::ITaskQueue::Token renderTask {};
156
LockCompositor()157 void LockCompositor()
158 {
159 mute.lock();
160 }
161
UnlockCompositor()162 void UnlockCompositor()
163 {
164 mute.unlock();
165 }
166
167 static constexpr BASE_NS::Uid ENGINE_THREAD { "2070e705-d061-40e4-bfb7-90fad2c280af" };
168 static constexpr BASE_NS::Uid APP_THREAD { "b2e8cef3-453a-4651-b564-5190f8b5190d" };
169 static constexpr BASE_NS::Uid IO_QUEUE { "be88e9a0-9cd8-45ab-be48-937953dc258f" };
170 static constexpr BASE_NS::Uid JS_RELEASE_THREAD { "3784fa96-b25b-4e9c-bbf1-e897d36f73af" };
171 static constexpr uint32_t FLOAT_TO_BYTE = sizeof(float) / sizeof(uint8_t);
172 static constexpr uint32_t TRANSFORM_MATRIX_SIZE = 16;
173 static const char* const RENDER_DATA_STORE_DEFAULT_STAGING = "RenderDataStoreDefaultStaging";
174 static const char* const ENV_PROPERTIES_BUFFER_NAME = "AR_CAMERA_TRANSFORM_MATRIX";
175 static constexpr uint64_t BUFFER_FENCE_HANDLE_BASE { 0xAAAAAAAAaaaaaaaa };
176 static constexpr uint32_t TIME_OUT_MILLISECONDS = 5000;
177
178 template<typename T>
LoadFunc(T & fn,const char * fName,void * handle)179 bool LoadFunc(T &fn, const char *fName, void* handle)
180 {
181 fn = reinterpret_cast<T>(dlsym(handle, fName));
182 if (fn == nullptr) {
183 WIDGET_LOGE("%s open %s", __func__, dlerror());
184 return false;
185 }
186 return true;
187 }
188
~SceneAdapter()189 SceneAdapter::~SceneAdapter()
190 {
191 }
192
SceneAdapter()193 SceneAdapter::SceneAdapter()
194 {
195 WIDGET_LOGD("scene adapter Impl create");
196 }
197
LoadEngineLib()198 bool SceneAdapter::LoadEngineLib()
199 {
200 if (engineInstance_.libHandle_ != nullptr) {
201 WIDGET_LOGD("%s, already loaded", __func__);
202 return true;
203 }
204
205 #define TO_STRING(name) #name
206 #define LIB_NAME(name) TO_STRING(name)
207 constexpr std::string_view lib { LIB_NAME(LIB_ENGINE_CORE)".so" };
208 engineInstance_.libHandle_ = dlopen(lib.data(), RTLD_LAZY);
209
210 if (engineInstance_.libHandle_ == nullptr) {
211 WIDGET_LOGE("%s, open lib fail %s", __func__, dlerror());
212 }
213 #undef TO_STRING
214 #undef LIB_NAME
215
216 #define LOAD_FUNC(fn, name) LoadFunc<decltype(fn)>(fn, name, engineInstance_.libHandle_)
217 if (!(LOAD_FUNC(CORE_NS::CreatePluginRegistry,
218 "_ZN4Core20CreatePluginRegistryERKNS_18PlatformCreateInfoE")
219 && LOAD_FUNC(CORE_NS::GetPluginRegister, "_ZN4Core17GetPluginRegisterEv")
220 && LOAD_FUNC(CORE_NS::IsDebugBuild, "_ZN4Core12IsDebugBuildEv")
221 && LOAD_FUNC(CORE_NS::GetVersion, "_ZN4Core13GetVersionRevEv"))) {
222 return false;
223 }
224 #undef LOAD_FUNC
225
226 return true;
227 }
228
LoadPlugins(const CORE_NS::PlatformCreateInfo & platformCreateInfo)229 bool SceneAdapter::LoadPlugins(const CORE_NS::PlatformCreateInfo& platformCreateInfo)
230 {
231 if (engineInstance_.libHandle_) {
232 WIDGET_LOGI("%s, already loaded", __func__);
233 return true;
234 }
235 if (!LoadEngineLib()) {
236 return false;
237 }
238 WIDGET_LOGD("load engine suceess!");
239
240 BASE_NS::vector<BASE_NS::Uid> DefaultPluginVector = {
241 CAM_PREVIEW_NS::UID_CAMERA_PREVIEW_PLUGIN,
242 SCENE_NS::UID_SCENE_PLUGIN,
243 #if defined(USE_LIB_PNG_JPEG_DYNAMIC_PLUGIN) && USE_LIB_PNG_JPEG_DYNAMIC_PLUGIN
244 JPGPlugin::UID_JPG_PLUGIN,
245 PNGPlugin::UID_PNG_PLUGIN,
246 #endif
247 };
248 const BASE_NS::array_view<BASE_NS::Uid> DefaultPluginList(DefaultPluginVector.data(), DefaultPluginVector.size());
249 CORE_NS::CreatePluginRegistry(platformCreateInfo);
250 if (!CORE_NS::GetPluginRegister().LoadPlugins(DefaultPluginList)) {
251 WIDGET_LOGE("fail to load scene widget plugin");
252 return false;
253 }
254 WIDGET_LOGI("load plugin success");
255 return true;
256 }
257
InitEngine(CORE_NS::PlatformCreateInfo platformCreateInfo)258 bool SceneAdapter::InitEngine(CORE_NS::PlatformCreateInfo platformCreateInfo)
259 {
260 auto& tr = META_NS::GetTaskQueueRegistry();
261 auto& obr = META_NS::GetObjectRegistry();
262
263 engineThread = tr.GetTaskQueue(ENGINE_THREAD);
264 if (!engineThread) {
265 engineThread = obr.Create<META_NS::ITaskQueue>(META_NS::ClassId::ThreadedTaskQueue);
266 tr.RegisterTaskQueue(engineThread, ENGINE_THREAD);
267 }
268 ioThread = tr.GetTaskQueue(IO_QUEUE);
269 if (!ioThread) {
270 ioThread = obr.Create<META_NS::ITaskQueue>(META_NS::ClassId::ThreadedTaskQueue);
271 tr.RegisterTaskQueue(ioThread, IO_QUEUE);
272 }
273 releaseThread = tr.GetTaskQueue(JS_RELEASE_THREAD);
274 if (!releaseThread) {
275 auto &obr = META_NS::GetObjectRegistry();
276 releaseThread = obr.Create<META_NS::ITaskQueue>(META_NS::ClassId::ThreadedTaskQueue);
277 tr.RegisterTaskQueue(releaseThread, JS_RELEASE_THREAD);
278 }
279
280 bool inited = false;
281 auto initCheck = META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>([&inited]() {
282 inited = (engineInstance_.engine_ != nullptr);
283 return META_NS::IAny::Ptr {};
284 });
285 engineThread->AddWaitableTask(initCheck)->Wait();
286 if (inited) {
287 WIDGET_LOGI("engine already inited");
288 return true;
289 }
290
291 auto engineInit = META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>([platformCreateInfo]() {
292 auto &obr = META_NS::GetObjectRegistry();
293 // Initialize lumeengine/render etc
294 CORE_NS::EngineCreateInfo engineCreateInfo{platformCreateInfo, {}, {}};
295 if (auto factory = CORE_NS::GetInstance<CORE_NS::IEngineFactory>(CORE_NS::UID_ENGINE_FACTORY)) {
296 engineInstance_.engine_.reset(factory->Create(engineCreateInfo).get());
297 } else {
298 WIDGET_LOGE("could not get engine factory");
299 return META_NS::IAny::Ptr {};
300 }
301 if (!engineInstance_.engine_) {
302 WIDGET_LOGE("get engine fail");
303 return META_NS::IAny::Ptr {};
304 }
305 auto &fileManager = engineInstance_.engine_->GetFileManager();
306 const auto &platform = engineInstance_.engine_->GetPlatform();
307 platform.RegisterDefaultPaths(fileManager);
308 engineInstance_.engine_->Init();
309
310 engineInstance_.renderContext_.reset(CORE_NS::CreateInstance<RENDER_NS::IRenderContext>(
311 *engineInstance_.engine_->GetInterface<Core::IClassFactory>(), RENDER_NS::UID_RENDER_CONTEXT).get());
312
313 RENDER_NS::RenderCreateInfo renderCreateInfo{};
314 RENDER_NS::BackendExtraGLES glExtra{};
315 Render::DeviceCreateInfo deviceCreateInfo{};
316
317 std::string backendProp = LumeRenderConfig::GetInstance().renderBackend_ == "force_vulkan" ? "vulkan" : "gles";
318 if (backendProp == "vulkan") {
319 WIDGET_LOGI("backend vulkan");
320 } else {
321 WIDGET_LOGI("backend gles");
322 glExtra.depthBits = 24; // 24 : bits size
323 glExtra.sharedContext = EGL_NO_CONTEXT;
324 deviceCreateInfo.backendType = RENDER_NS::DeviceBackendType::OPENGLES;
325 deviceCreateInfo.backendConfiguration = &glExtra;
326 renderCreateInfo.applicationInfo = {};
327 renderCreateInfo.deviceCreateInfo = deviceCreateInfo;
328 }
329
330 auto rrc = engineInstance_.renderContext_->Init(renderCreateInfo);
331 if (rrc != RENDER_NS::RenderResultCode::RENDER_SUCCESS) {
332 WIDGET_LOGE("Failed to create render context");
333 return META_NS::IAny::Ptr {};
334 }
335
336 // Save the stuff to the default object context.
337 auto engineThread = META_NS::GetTaskQueueRegistry().GetTaskQueue(ENGINE_THREAD);
338 // thats the javascript thread...
339 auto appThread = engineThread;
340 auto doc = interface_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
341 if (doc == nullptr) {
342 WIDGET_LOGE("nullptr from interface_cast");
343 return META_NS::IAny::Ptr {};
344 }
345 auto flags = META_NS::ObjectFlagBits::INTERNAL | META_NS::ObjectFlagBits::NATIVE;
346
347 doc->AddProperty(META_NS::ConstructProperty<IntfPtr>("RenderContext", nullptr, flags));
348 doc->AddProperty(META_NS::ConstructProperty<IntfPtr>("EngineQueue", nullptr, flags));
349 doc->AddProperty(META_NS::ConstructProperty<IntfPtr>("AppQueue", nullptr, flags));
350 doc->AddProperty(META_NS::ConstructArrayProperty<IntfWeakPtr>("Scenes", {}, flags));
351
352 doc->GetProperty<META_NS::SharedPtrIInterface>("EngineQueue")->SetValue(engineThread);
353 doc->GetProperty<META_NS::SharedPtrIInterface>("AppQueue")->SetValue(appThread);
354 doc->GetProperty<META_NS::SharedPtrIInterface>("RenderContext")->SetValue(engineInstance_.renderContext_);
355
356 WIDGET_LOGD("register shader paths");
357 static constexpr const RENDER_NS::IShaderManager::ShaderFilePathDesc desc { "shaders://" };
358 engineInstance_.engine_->GetFileManager().RegisterPath("shaders", "OhosRawFile://shaders", false);
359 engineInstance_.renderContext_->GetDevice().GetShaderManager().LoadShaderFiles(desc);
360
361 engineInstance_.engine_->GetFileManager().RegisterPath("appshaders", "OhosRawFile://shaders", false);
362 engineInstance_.engine_->GetFileManager().RegisterPath("apppipelinelayouts",
363 "OhosRawFile:///pipelinelayouts/", true);
364 engineInstance_.engine_->GetFileManager().RegisterPath("fonts", "OhosRawFile:///fonts", true);
365
366 static constexpr const RENDER_NS::IShaderManager::ShaderFilePathDesc desc1 { "appshaders://" };
367 engineInstance_.renderContext_->GetDevice().GetShaderManager().LoadShaderFiles(desc1);
368
369 // "render" one frame. this is to initialize all the default resources etc.
370 // if we never render a single frame, we will get "false positive" leaks of gpu resources.
371 engineInstance_.renderContext_->GetRenderer().RenderFrame({});
372 WIDGET_LOGI("init engine success");
373 return META_NS::IAny::Ptr {};
374 });
375 engineThread->AddWaitableTask(engineInit)->Wait();
376 return true;
377 }
378
SetSceneObj(META_NS::IObject::Ptr pt)379 void SceneAdapter::SetSceneObj(META_NS::IObject::Ptr pt)
380 {
381 WIDGET_LOGD("SceneAdapterImpl::SetSceneObj");
382 sceneWidgetObj_ = pt;
383 }
384
CreateTextureLayer()385 std::shared_ptr<TextureLayer> SceneAdapter::CreateTextureLayer()
386 {
387 WIDGET_LOGI("SceneAdapter::CreateTextureLayer: %u", key_);
388 auto cb = META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>([this]() {
389 textureLayer_ = std::make_shared<TextureLayer>(key_);
390 key_++;
391 return META_NS::IAny::Ptr {};
392 });
393 if (engineThread) {
394 engineThread->AddWaitableTask(cb)->Wait();
395 } else {
396 WIDGET_LOGE("ENGINE_THREAD not ready in CreateTextureLayer");
397 }
398 return textureLayer_;
399 }
400
LoadPluginsAndInit()401 bool SceneAdapter::LoadPluginsAndInit()
402 {
403 LockCompositor(); // an APP_FREEZE here, so add lock just in case, but suspect others' error
404 WIDGET_LOGI("scene adapter loadPlugins");
405
406 if (hapInfo_.hapPath_ == "") {
407 hapInfo_ = GetHapInfo();
408 }
409
410 #define TO_STRING(name) #name
411 #define PLATFORM_PATH_NAME(name) TO_STRING(name)
412 CORE_NS::PlatformCreateInfo platformCreateInfo {
413 PLATFORM_PATH_NAME(PLATFORM_CORE_ROOT_PATH),
414 PLATFORM_PATH_NAME(PLATFORM_CORE_PLUGIN_PATH),
415 PLATFORM_PATH_NAME(PLATFORM_APP_ROOT_PATH),
416 PLATFORM_PATH_NAME(PLATFORM_APP_PLUGIN_PATH),
417 hapInfo_.hapPath_.c_str(),
418 hapInfo_.bundleName_.c_str(),
419 hapInfo_.moduleName_.c_str(),
420 hapInfo_.resourceManager_
421 };
422 #undef TO_STRING
423 #undef PLATFORM_PATH_NAME
424 if (!LoadPlugins(platformCreateInfo)) {
425 UnlockCompositor();
426 return false;
427 }
428
429 if (!InitEngine(platformCreateInfo)) {
430 UnlockCompositor();
431 return false;
432 }
433
434 CreateRenderFunction();
435 UnlockCompositor();
436 return true;
437 }
438
OnWindowChange(const WindowChangeInfo & windowChangeInfo)439 void SceneAdapter::OnWindowChange(const WindowChangeInfo &windowChangeInfo)
440 {
441 WIDGET_LOGI("SceneAdapter::OnWindowchange");
442 auto cb = META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>([this, &windowChangeInfo]() {
443 if (!textureLayer_) {
444 WIDGET_LOGE("textureLayer is null in OnWindowChange");
445 return META_NS::IAny::Ptr {};
446 }
447 textureLayer_->OnWindowChange(windowChangeInfo);
448 const auto& textureInfo = textureLayer_->GetTextureInfo();
449 auto& device = engineInstance_.renderContext_->GetDevice();
450 RENDER_NS::SwapchainCreateInfo swapchainCreateInfo {
451 0U,
452 RENDER_NS::SwapchainFlagBits::CORE_SWAPCHAIN_COLOR_BUFFER_BIT |
453 RENDER_NS::SwapchainFlagBits::CORE_SWAPCHAIN_DEPTH_BUFFER_BIT |
454 RENDER_NS::SwapchainFlagBits::CORE_SWAPCHAIN_SRGB_BIT,
455 RENDER_NS::ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
456 {
457 reinterpret_cast<uintptr_t>(textureInfo.nativeWindow_),
458 reinterpret_cast<uintptr_t>(static_cast<const RENDER_NS::DevicePlatformDataGLES&>(
459 device.GetPlatformData()).display)
460 }
461 };
462 swapchainHandle_ = device.CreateSwapchainHandle(swapchainCreateInfo, swapchainHandle_, {});
463 if (auto scene = interface_pointer_cast<SCENE_NS::IScene>(sceneWidgetObj_)) {
464 auto cams = scene->GetCameras().GetResult();
465 if (!cams.empty()) {
466 for (auto c : cams) {
467 AttachSwapchain(interface_pointer_cast<META_NS::IObject>(c));
468 }
469 }
470 }
471 return META_NS::IAny::Ptr {};
472 });
473
474 if (engineThread) {
475 engineThread->AddWaitableTask(cb)->Wait();
476 } else {
477 WIDGET_LOGE("ENGINE_THREAD not ready in OnWindowChange");
478 }
479 }
480
CreateRenderFunction()481 void SceneAdapter::CreateRenderFunction()
482 {
483 propSyncSync_ = META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>([this]() {
484 PropSync();
485 return META_NS::IAny::Ptr {};
486 });
487 // Task used for oneshot renders
488 singleFrameAsync_ = META_NS::MakeCallback<META_NS::ITaskQueueTask>([this]() {
489 RenderFunction();
490 return 0;
491 });
492 // Task used for oneshot synchronous renders
493 singleFrameSync_ = META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>([this]() {
494 RenderFunction();
495 return META_NS::IAny::Ptr {};
496 });
497 }
498
DeinitRenderThread()499 void SceneAdapter::DeinitRenderThread()
500 {
501 RETURN_IF_NULL(engineThread);
502 if (renderTask) {
503 engineThread->CancelTask(renderTask);
504 renderTask = nullptr;
505 }
506 auto engine_deinit = META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>([]() {
507 // destroy all swapchains
508 auto &obr = META_NS::GetObjectRegistry();
509 auto doc = interface_cast<META_NS::IMetadata>(obr.GetDefaultObjectContext());
510 if (doc == nullptr) {
511 WIDGET_LOGE("nullptr from interface_cast");
512 return META_NS::IAny::Ptr {};
513 }
514 // hmm.. this is somewhat uncool
515 {
516 auto p1 = doc->GetProperty<IntfPtr>("EngineQueue");
517 doc->RemoveProperty(p1);
518 auto p2 = doc->GetProperty<IntfPtr>("AppQueue");
519 doc->RemoveProperty(p2);
520 auto p3 = doc->GetProperty<IntfPtr>("RenderContext");
521 doc->RemoveProperty(p3);
522 }
523
524 doc->GetArrayProperty<IntfWeakPtr>("Scenes")->Reset();
525 engineInstance_.renderContext_.reset();
526 engineInstance_.engine_.reset();
527
528 return META_NS::IAny::Ptr{};
529 });
530 engineThread->AddWaitableTask(engine_deinit)->Wait();
531 auto &tr = META_NS::GetTaskQueueRegistry();
532 tr.UnregisterTaskQueue(ENGINE_THREAD);
533 engineThread.reset();
534 tr.UnregisterTaskQueue(IO_QUEUE);
535 ioThread.reset();
536 tr.UnregisterTaskQueue(JS_RELEASE_THREAD);
537 releaseThread.reset();
538 }
539
ShutdownPluginRegistry()540 void SceneAdapter::ShutdownPluginRegistry()
541 {
542 if (engineInstance_.libHandle_ == nullptr) {
543 return;
544 }
545 dlclose(engineInstance_.libHandle_);
546 engineInstance_.libHandle_ = nullptr;
547
548 CORE_NS::GetPluginRegister = nullptr;
549 CORE_NS::CreatePluginRegistry = nullptr;
550 CORE_NS::IsDebugBuild = nullptr;
551 CORE_NS::GetVersion = nullptr;
552 }
553
PropSync()554 void SceneAdapter::PropSync()
555 {
556 auto scene = interface_pointer_cast<SCENE_NS::IScene>(sceneWidgetObj_);
557 if (!scene) {
558 return;
559 }
560 auto internal = scene->GetInternalScene();
561 if (!internal) {
562 return;
563 }
564 internal->SyncProperties();
565 }
566
RenderFunction()567 void SceneAdapter::RenderFunction()
568 {
569 WIDGET_SCOPED_TRACE("SceneAdapter::RenderFunction");
570 auto rc = engineInstance_.renderContext_;
571 RETURN_IF_NULL(rc);
572 RETURN_IF_NULL(sceneWidgetObj_);
573 auto scene = interface_pointer_cast<SCENE_NS::IScene>(sceneWidgetObj_);
574 RETURN_IF_NULL(scene);
575 if (!bitmap_) {
576 auto cams = scene->GetCameras().GetResult();
577 if (!cams.empty()) {
578 for (auto c : cams) {
579 AttachSwapchain(interface_pointer_cast<META_NS::IObject>(c));
580 }
581 }
582 }
583 scene->GetInternalScene()->Update(false);
584 bool receiveBuffer = receiveBuffer_;
585 receiveBuffer_ = false;
586
587 auto& renderFrameUtil = rc->GetRenderUtil().GetRenderFrameUtil();
588 auto backendType = rc->GetDevice().GetBackendType();
589 if (receiveBuffer) {
590 if (sfBufferInfo_.acquireFence_) {
591 int32_t ret = sfBufferInfo_.acquireFence_->Wait(TIME_OUT_MILLISECONDS);
592 if (sfBufferInfo_.acquireFence_->Get() >= 0 && ret < 0) {
593 WIDGET_LOGE("wait fence error: %d", ret);
594 }
595 sfBufferInfo_.acquireFence_ = nullptr;
596 }
597 if (backendType == RENDER_NS::DeviceBackendType::VULKAN) {
598 // NOTE: vulkan not implemented yet
599 WIDGET_LOGD("vulkan fence");
600 } else if (backendType == RENDER_NS::DeviceBackendType::OPENGLES) {
601 RENDER_NS::IRenderFrameUtil::SignalData signalData;
602 signalData.signaled = false;
603 signalData.signalResourceType = RENDER_NS::IRenderFrameUtil::SignalResourceType::GPU_FENCE;
604 signalData.handle = bufferFenceHandle_;
605 renderFrameUtil.AddGpuSignal(signalData);
606 }
607 }
608 rc->GetRenderer().RenderDeferredFrame();
609 if (receiveBuffer) {
610 auto addedSD = renderFrameUtil.GetFrameGpuSignalData();
611 for (const auto& ref : addedSD) {
612 if (ref.handle.GetHandle().id == bufferFenceHandle_.GetHandle().id) {
613 int32_t fenceFileDesc = CreateFenceFD(ref, rc->GetDevice());
614 sfBufferInfo_.fn_(fenceFileDesc);
615 break;
616 }
617 }
618 }
619 }
620
CreateFenceFD(const RENDER_NS::IRenderFrameUtil::SignalData & signalData,RENDER_NS::IDevice & device)621 int32_t SceneAdapter::CreateFenceFD(
622 const RENDER_NS::IRenderFrameUtil::SignalData &signalData, RENDER_NS::IDevice &device)
623 {
624 int32_t fenceFileDesc = -1;
625 auto backendType = device.GetBackendType();
626 if (backendType == RENDER_NS::DeviceBackendType::VULKAN) {
627 // NOTE: vulkan not implemented yet
628 WIDGET_LOGD("vulkan fence");
629 } else if (backendType == RENDER_NS::DeviceBackendType::OPENGLES) {
630 const auto disp = static_cast<const RENDER_NS::DevicePlatformDataGLES &>(device.GetPlatformData()).display;
631 EGLSyncKHR sync = reinterpret_cast<EGLSyncKHR>(static_cast<uintptr_t>(signalData.gpuSignalResourceHandle));
632 if (sync == EGL_NO_SYNC_KHR) {
633 WIDGET_LOGE("invalid EGLSync from signal data");
634 return fenceFileDesc;
635 }
636 fenceFileDesc = eglDupNativeFenceFDANDROID(disp, sync);
637 if (fenceFileDesc == -1) {
638 WIDGET_LOGE("eglDupNativeFence fail");
639 }
640 } else {
641 WIDGET_LOGE("no supported backend");
642 }
643 return fenceFileDesc;
644 }
645
RenderFrame(bool needsSyncPaint)646 void SceneAdapter::RenderFrame(bool needsSyncPaint)
647 {
648 if (!engineThread) {
649 WIDGET_LOGE("no engineThread for Render");
650 return;
651 }
652 if (renderTask) {
653 engineThread->CancelTask(renderTask);
654 renderTask = nullptr;
655 }
656
657 if (!singleFrameAsync_ || !singleFrameSync_ || !propSyncSync_) {
658 CreateRenderFunction();
659 }
660
661 if (propSyncSync_) {
662 WIDGET_SCOPED_TRACE("SceneAdapter::propSyncSync_");
663 engineThread->AddWaitableTask(propSyncSync_)->Wait();
664 }
665
666 if (!needsSyncPaint && singleFrameAsync_) {
667 renderTask = engineThread->AddTask(singleFrameAsync_);
668 } else if (singleFrameSync_) {
669 engineThread->AddWaitableTask(singleFrameSync_)->Wait();
670 } else {
671 WIDGET_LOGE("No render function available.");
672 }
673 }
674
NeedsRepaint()675 bool SceneAdapter::NeedsRepaint()
676 {
677 return needsRepaint_;
678 }
679
SetNeedsRepaint(bool needsRepaint)680 void SceneAdapter::SetNeedsRepaint(bool needsRepaint)
681 {
682 needsRepaint_ = needsRepaint;
683 }
684
Deinit()685 void SceneAdapter::Deinit()
686 {
687 RETURN_IF_NULL(engineThread);
688 WIDGET_LOGI("SceneAdapter::Deinit");
689 auto func = META_NS::MakeCallback<META_NS::ITaskQueueWaitableTask>([this]() {
690 if (bitmap_) {
691 auto scene = interface_pointer_cast<SCENE_NS::IScene>(sceneWidgetObj_);
692 if (!scene) {
693 return META_NS::IAny::Ptr {};
694 }
695 if (auto i = interface_cast<SCENE_NS::IRenderResource>(bitmap_)) {
696 i->SetRenderHandle(scene->GetInternalScene(), swapchainHandle_);
697 }
698 }
699 if (swapchainHandle_) {
700 auto& device = engineInstance_.renderContext_->GetDevice();
701 device.DestroySwapchain(swapchainHandle_);
702 }
703 swapchainHandle_ = {};
704 return META_NS::IAny::Ptr {};
705 });
706 engineThread->AddWaitableTask(func)->Wait();
707
708 sceneWidgetObj_.reset();
709 singleFrameAsync_.reset();
710 singleFrameSync_.reset();
711 propSyncSync_.reset();
712 needsRepaint_ = false;
713 }
714
AttachSwapchain(META_NS::IObject::Ptr cameraObj)715 void SceneAdapter::AttachSwapchain(META_NS::IObject::Ptr cameraObj)
716 {
717 WIDGET_LOGI("attach swapchain");
718 if (!swapchainHandle_) {
719 return;
720 }
721 auto node = interface_cast<SCENE_NS::INode>(cameraObj);
722 if (node == nullptr) {
723 WIDGET_LOGE("cast cameraObj failed in AttachSwapchain.");
724 return;
725 }
726 auto scene = node->GetScene();
727 auto camera = interface_pointer_cast<SCENE_NS::ICamera>(cameraObj);
728 if (!camera->IsActive()) {
729 return;
730 }
731
732 bitmap_ = META_NS::GetObjectRegistry().Create<SCENE_NS::IRenderTarget>(SCENE_NS::ClassId::Bitmap);
733 if (auto i = interface_cast<SCENE_NS::IRenderResource>(bitmap_)) {
734 i->SetRenderHandle(scene->GetInternalScene(), swapchainHandle_);
735 }
736 camera->SetRenderTarget(bitmap_);
737 }
738
739 namespace {
CreateOESTextureHandle(CORE_NS::IEcs::Ptr ecs,BASE_NS::shared_ptr<RENDER_NS::IRenderContext> renderContext,const SurfaceBufferInfo & surfaceBufferInfo)740 RENDER_NS::RenderHandleReference CreateOESTextureHandle(CORE_NS::IEcs::Ptr ecs,
741 BASE_NS::shared_ptr<RENDER_NS::IRenderContext> renderContext, const SurfaceBufferInfo &surfaceBufferInfo)
742 {
743 if (!ecs || !renderContext) {
744 WIDGET_LOGE("null ecs or renderContext");
745 return {};
746 }
747 auto surfaceBuffer = surfaceBufferInfo.sfBuffer_;
748 if (!surfaceBuffer) {
749 WIDGET_LOGE("surface buffer null");
750 return {};
751 }
752 auto nativeBuffer = surfaceBuffer->SurfaceBufferToNativeBuffer();
753 if (!nativeBuffer) {
754 WIDGET_LOGE("surface buffer to native buffer fail");
755 return {};
756 }
757
758 std::shared_ptr<RENDER_NS::BackendSpecificImageDesc> data = nullptr;
759 auto backendType = renderContext->GetDevice().GetBackendType();
760 if (backendType == RENDER_NS::DeviceBackendType::VULKAN) {
761 // NOTE: vulkan not implemented yet
762 data = std::make_shared<RENDER_NS::ImageDescVk>();
763 auto vkData = std::static_pointer_cast<RENDER_NS::ImageDescVk>(data);
764 vkData->platformHwBuffer = reinterpret_cast<uintptr_t>(nativeBuffer);
765 } else if (backendType == RENDER_NS::DeviceBackendType::OPENGLES) {
766 data = std::make_shared<RENDER_NS::ImageDescGLES>();
767 auto glesData = std::static_pointer_cast<RENDER_NS::ImageDescGLES>(data);
768 glesData->type = GL_TEXTURE_EXTERNAL_OES;
769 glesData->platformHwBuffer = reinterpret_cast<uintptr_t>(nativeBuffer);
770 }
771
772 if (!data) {
773 WIDGET_LOGE("create ImageDesc based on backend fail!");
774 return {};
775 }
776
777 auto &gpuResourceManager = renderContext->GetDevice().GetGpuResourceManager();
778 auto handle = gpuResourceManager.CreateView("AR_CAMERA_PREVIEW", {}, *data);
779
780 return handle;
781 }
782 } // namespace
783
InitEnvironmentResource(const uint32_t bufferSize)784 void SceneAdapter::InitEnvironmentResource(const uint32_t bufferSize)
785 {
786 WIDGET_LOGI("Init resource for camera view");
787 auto scene = interface_pointer_cast<SCENE_NS::IScene>(sceneWidgetObj_);
788 RETURN_IF_NULL(scene);
789 auto internalScene = scene->GetInternalScene();
790 RETURN_IF_NULL(internalScene);
791 auto ecs = internalScene->GetEcsContext().GetNativeEcs();
792 RETURN_IF_NULL(ecs);
793 auto renderContext = engineInstance_.renderContext_;
794 RETURN_IF_NULL(renderContext);
795
796 bufferFenceHandle_ = RENDER_NS::RenderHandleReference{{static_cast<uint64_t>(key_) + BUFFER_FENCE_HANDLE_BASE}, {}};
797
798 auto envManager = CORE_NS::GetManager<CORE3D_NS::IEnvironmentComponentManager>(*ecs);
799 RETURN_IF_NULL(envManager);
800 const auto &shaderMgr = renderContext->GetDevice().GetShaderManager();
801 auto &entityManager = (*ecs).GetEntityManager();
802 auto renderHandleManager = CORE_NS::GetManager<CORE3D_NS::IRenderHandleComponentManager>(*ecs);
803 RETURN_IF_NULL(renderHandleManager);
804 auto uriManager = CORE_NS::GetManager<CORE3D_NS::IUriComponentManager>(*ecs);
805 RETURN_IF_NULL(uriManager);
806
807 CORE_NS::EntityReference shaderEF = entityManager.CreateReferenceCounted();
808 renderHandleManager->Create(shaderEF);
809 BASE_NS::string_view shaderUri = "campreviewshaders://shader/camera_stream.shader";
810 renderContext->GetDevice().GetShaderManager().LoadShaderFile(shaderUri.data());
811 if (auto renderEntityHandle = renderHandleManager->Write(shaderEF)) {
812 renderEntityHandle->reference = shaderMgr.GetShaderHandle(shaderUri);
813 }
814 uriManager->Create(shaderEF);
815 if (auto uriHandle = uriManager->Write(shaderEF)) {
816 uriHandle->uri = shaderUri;
817 }
818
819 RENDER_NS::GpuBufferDesc envBufferDesc{
820 RENDER_NS::CORE_BUFFER_USAGE_UNIFORM_BUFFER_BIT | RENDER_NS::CORE_BUFFER_USAGE_TRANSFER_DST_BIT,
821 RENDER_NS::CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT | RENDER_NS::CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT,
822 RENDER_NS::CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER,
823 bufferSize};
824 BASE_NS::array_view<const uint8_t> transData(
825 reinterpret_cast<const uint8_t *>(sfBufferInfo_.transformMatrix_.data()), bufferSize);
826 camTransBufferHandle_ =
827 renderContext->GetDevice().GetGpuResourceManager().Create(ENV_PROPERTIES_BUFFER_NAME, envBufferDesc, transData);
828 CORE_NS::EntityReference transBufferEF = entityManager.CreateReferenceCounted();
829 renderHandleManager->Create(transBufferEF);
830 if (auto renderEntityHandle = renderHandleManager->Write(transBufferEF)) {
831 renderEntityHandle->reference = camTransBufferHandle_;
832 }
833
834 CORE_NS::EntityReference transBufferEF2 = entityManager.CreateReferenceCounted();
835 renderHandleManager->Create(transBufferEF2);
836 if (auto renderEntityHandle = renderHandleManager->Write(transBufferEF2)) {
837 renderEntityHandle->reference = camTransBufferHandle_;
838 }
839
840 CORE_NS::EntityReference transBufferEF3 = entityManager.CreateReferenceCounted();
841 renderHandleManager->Create(transBufferEF3);
842 if (auto renderEntityHandle = renderHandleManager->Write(transBufferEF3)) {
843 renderEntityHandle->reference = camTransBufferHandle_;
844 }
845
846 camImageEF_ = entityManager.CreateReferenceCounted();
847 renderHandleManager->Create(camImageEF_);
848
849 if (auto rc = scene->RenderConfiguration()->GetValue()) {
850 if (auto env = rc->Environment()->GetValue()) {
851 CORE_NS::Entity environmentEntity = interface_pointer_cast<SCENE_NS::IEcsObjectAccess>(env)->
852 GetEcsObject()->GetEntity();
853 if (auto envDataHandle = envManager->Write(environmentEntity)) {
854 CORE3D_NS::EnvironmentComponent &envComponent = *envDataHandle;
855 envComponent.background = CORE3D_NS::EnvironmentComponent::Background::IMAGE;
856 envComponent.shader = shaderEF;
857 envComponent.customResources.push_back({camImageEF_});
858 envComponent.customResources.push_back({transBufferEF});
859 envComponent.customResources.push_back({transBufferEF2});
860 envComponent.customResources.push_back({transBufferEF3});
861 }
862 }
863 }
864 if (!renderDataStoreDefaultStaging_) {
865 renderDataStoreDefaultStaging_ = BASE_NS::refcnt_ptr<RENDER_NS::IRenderDataStoreDefaultStaging>(
866 static_cast<RENDER_NS::IRenderDataStoreDefaultStaging *>(
867 renderContext->GetRenderDataStoreManager().GetRenderDataStore(RENDER_DATA_STORE_DEFAULT_STAGING).get()));
868 RETURN_IF_NULL(renderDataStoreDefaultStaging_);
869 }
870 }
871
UpdateSurfaceBuffer()872 void SceneAdapter::UpdateSurfaceBuffer()
873 {
874 auto scene = interface_pointer_cast<SCENE_NS::IScene>(sceneWidgetObj_);
875 RETURN_IF_NULL(scene);
876 auto internalScene = scene->GetInternalScene();
877 RETURN_IF_NULL(internalScene);
878 auto ecs = internalScene->GetEcsContext().GetNativeEcs();
879 RETURN_IF_NULL(ecs);
880 auto renderContext = engineInstance_.renderContext_;
881 RETURN_IF_NULL(renderContext);
882
883 auto viewHandle = CreateOESTextureHandle(ecs, renderContext, sfBufferInfo_);
884 RETURN_IF_NULL(viewHandle);
885
886 const uint32_t bufferSize = sfBufferInfo_.transformMatrix_.size() * FLOAT_TO_BYTE;
887 if (bufferSize < TRANSFORM_MATRIX_SIZE * FLOAT_TO_BYTE) {
888 WIDGET_LOGE("transform matrix size:%d not 4x4", bufferSize / FLOAT_TO_BYTE);
889 const float *arr = BASE_NS::Math::IDENTITY_4X4.data;
890 sfBufferInfo_.transformMatrix_.assign(arr, arr + TRANSFORM_MATRIX_SIZE);
891 } else if (bufferSize > TRANSFORM_MATRIX_SIZE * FLOAT_TO_BYTE) {
892 WIDGET_LOGE("transform matrix size:%d not 4x4", bufferSize / FLOAT_TO_BYTE);
893 }
894
895 if (!initCamRNG_) {
896 InitEnvironmentResource(bufferSize);
897 initCamRNG_ = true;
898 }
899
900 if (auto renderHandleManager = CORE_NS::GetManager<CORE3D_NS::IRenderHandleComponentManager>(*ecs)) {
901 if (auto camImageRenderHandle = renderHandleManager->Write(camImageEF_)) {
902 camImageRenderHandle->reference = viewHandle;
903 }
904 }
905
906 if (camTransBufferHandle_ && renderDataStoreDefaultStaging_) {
907 BASE_NS::array_view<const uint8_t> transData(
908 reinterpret_cast<const uint8_t *>(sfBufferInfo_.transformMatrix_.data()), bufferSize);
909 const RENDER_NS::BufferCopy bufferCopy{0, 0, bufferSize};
910 renderDataStoreDefaultStaging_->CopyDataToBufferOnCpu(transData, camTransBufferHandle_, bufferCopy);
911 }
912 }
913
AcquireImage(const SurfaceBufferInfo & bufferInfo)914 void SceneAdapter::AcquireImage(const SurfaceBufferInfo &bufferInfo)
915 {
916 RETURN_IF_NULL(engineThread);
917 engineThread->AddTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>([this, bufferInfo]() {
918 sfBufferInfo_ = bufferInfo;
919 receiveBuffer_ = true;
920 UpdateSurfaceBuffer();
921 return false;
922 }));
923 }
924 } // namespace OHOS::Render3D
925