/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "scene_init.h" #include "scene_adapter/scene_adapter.h" #include "3d_widget_adapter_log.h" #include "scene_adapter/scene_adapter.h" #include #include #include #include "napi/native_api.h" #include "napi/native_node_api.h" #include #include #include #include #include #include #include #include #include #include #include <3d/implementation_uids.h> #include <3d/intf_graphics_context.h> #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "napi_base_context.h" #include #include #include #include #include "3d_widget_adapter_log.h" #include "widget_trace.h" #include "ohos/texture_layer.h" CORE_BEGIN_NAMESPACE() /** Get plugin register */ IPluginRegister &(*GetPluginRegister)() = nullptr; /** Setup the plugin register */ void (*CreatePluginRegistry)(const struct PlatformCreateInfo &platformCreateInfo) = nullptr; /** Get whether engine is build in debug mode */ bool (*IsDebugBuild)() = nullptr; /** Get version */ BASE_NS::string_view (*GetVersion)() = nullptr; CORE_END_NAMESPACE() namespace OHOS::FUZZ { // class SceneInit : public ISceneInit { class SceneInit : public ISceneInit { public: SceneInit(); bool LoadPluginsAndInit() override; std::shared_ptr CreateTextureLayer() override; void OnWindowChange(const Render3D::WindowChangeInfo &windowChangeInfo) override; void RenderFrame(bool needsSyncPaint = false) override; EngineInstance& GetEngineInstance() override; void Deinit() override; bool NeedsRepaint() override { return false; } static void ShutdownPluginRegistry(); static void DeinitRenderThread(); ~SceneInit(); private: static bool LoadEngineLib(); bool LoadPlugins(const CORE_NS::PlatformCreateInfo &platformCreateInfo); bool InitEngine(CORE_NS::PlatformCreateInfo platformCreateInfo); void AttachSwapchain(META_NS::IObject::Ptr camera, RENDER_NS::RenderHandleReference swapchain); void RenderFunction(); void CreateRenderFunction(); std::shared_ptr scene_; }; Render3D::HapInfo GetHapInfo() { return {}; } using IntfPtr = META_NS::SharedPtrIInterface; using IntfWeakPtr = META_NS::WeakPtrIInterface; static EngineInstance engineInstance_; static std::mutex mute; static Render3D::HapInfo hapInfo_; META_NS::ITaskQueue::Ptr engineThread; META_NS::ITaskQueue::Ptr ioThread; META_NS::ITaskQueue::Ptr releaseThread; META_NS::ITaskQueue::Token renderTask{}; EngineInstance& SceneInit::GetEngineInstance() { return engineInstance_; } void LockCompositor() { mute.lock(); } void UnlockCompositor() { mute.unlock(); } static constexpr BASE_NS::Uid ENGINE_THREAD{"2070e705-d061-40e4-bfb7-90fad2c280af"}; static constexpr BASE_NS::Uid APP_THREAD{"b2e8cef3-453a-4651-b564-5190f8b5190d"}; static constexpr BASE_NS::Uid IO_QUEUE{"be88e9a0-9cd8-45ab-be48-937953dc258f"}; static constexpr BASE_NS::Uid JS_RELEASE_THREAD{"3784fa96-b25b-4e9c-bbf1-e897d36f73af"}; template bool LoadFunc(T &fn, const char *fName, void *handle) { fn = reinterpret_cast(dlsym(handle, fName)); if (fn == nullptr) { WIDGET_LOGE("%s open %s", __func__, dlerror()); return false; } return true; } SceneInit::SceneInit() { WIDGET_LOGD("scene adapter Impl create"); } bool SceneInit::LoadEngineLib() { if (engineInstance_.libHandle_ != nullptr) { WIDGET_LOGD("%s, already loaded", __func__); return true; } #define TO_STRING(name) #name #define LIB_NAME(name) TO_STRING(name) constexpr std::string_view lib{LIB_NAME(LIB_ENGINE_CORE) ".so"}; engineInstance_.libHandle_ = dlopen(lib.data(), RTLD_LAZY); if (engineInstance_.libHandle_ == nullptr) { WIDGET_LOGE("%s, open lib fail %s", __func__, dlerror()); } #undef TO_STRING #undef LIB_NAME #define LOAD_FUNC(fn, name) LoadFunc(fn, name, engineInstance_.libHandle_) if (!(LOAD_FUNC(CORE_NS::CreatePluginRegistry, "_ZN4Core20CreatePluginRegistryERKNS_18PlatformCreateInfoE") && LOAD_FUNC(CORE_NS::GetPluginRegister, "_ZN4Core17GetPluginRegisterEv") && LOAD_FUNC(CORE_NS::IsDebugBuild, "_ZN4Core12IsDebugBuildEv") && LOAD_FUNC(CORE_NS::GetVersion, "_ZN4Core13GetVersionRevEv"))) { return false; } #undef LOAD_FUNC return true; } bool SceneInit::LoadPlugins(const CORE_NS::PlatformCreateInfo &platformCreateInfo) { if (engineInstance_.libsLoaded_) { return true; } if (!LoadEngineLib()) { return false; } engineInstance_.libsLoaded_ = true; WIDGET_LOGD("load engine success!"); return true; } bool SceneInit::InitEngine(CORE_NS::PlatformCreateInfo platformCreateInfo) { #ifdef SCENE_META_FUZZ auto &tr = META_NS::GetTaskQueueRegistry(); auto &obr = META_NS::GetObjectRegistry(); engineThread = tr.GetTaskQueue(ENGINE_THREAD); if (!engineThread) { engineThread = obr.Create(META_NS::ClassId::ThreadedTaskQueue); tr.RegisterTaskQueue(engineThread, ENGINE_THREAD); } ioThread = tr.GetTaskQueue(IO_QUEUE); if (!ioThread) { ioThread = obr.Create(META_NS::ClassId::ThreadedTaskQueue); tr.RegisterTaskQueue(ioThread, IO_QUEUE); } releaseThread = tr.GetTaskQueue(JS_RELEASE_THREAD); if (!releaseThread) { auto &obr = META_NS::GetObjectRegistry(); releaseThread = obr.Create(META_NS::ClassId::ThreadedTaskQueue); tr.RegisterTaskQueue(releaseThread, JS_RELEASE_THREAD); } auto engineInit = META_NS::MakeCallback([platformCreateInfo]() { #endif // Initialize lumeengine/render etc #ifdef SCENE_META_FUZZ const BASE_NS::Uid DefaultPluginList[] { SCENE_NS::UID_SCENE_PLUGIN }; #else const BASE_NS::Uid DefaultPluginList[] { RENDER_NS::UID_RENDER_PLUGIN, CORE3D_NS::UID_3D_PLUGIN }; #endif CORE_NS::CreatePluginRegistry(platformCreateInfo); if (!CORE_NS::GetPluginRegister().LoadPlugins(DefaultPluginList)) { WIDGET_LOGE("fail to load scene widget plugin"); return false; } WIDGET_LOGI("load plugin success"); CORE_NS::EngineCreateInfo engineCreateInfo{platformCreateInfo, {}, {}}; if (auto factory = CORE_NS::GetInstance(CORE_NS::UID_ENGINE_FACTORY)) { engineInstance_.engine_.reset(factory->Create(engineCreateInfo).get()); } if (!engineInstance_.engine_) { WIDGET_LOGE("get engine fail"); return false; } engineInstance_.engine_->Init(); engineInstance_.renderContext_.reset( CORE_NS::CreateInstance(*engineInstance_.engine_, RENDER_NS::UID_RENDER_CONTEXT) .get()); if (!engineInstance_.renderContext_) { WIDGET_LOGE("get render context fail"); return false; } RENDER_NS::RenderCreateInfo renderCreateInfo; RENDER_NS::BackendExtraGLES glExtra; Render::DeviceCreateInfo deviceCreateInfo; // this context needs to be "not busy" (not selected current in any thread) for creation to succeed. // vulkan currently has no bloom std::string backendProp = "gles"; // Render3D::RenderConfig::GetInstance().renderBackend_ == "force_vulkan" ? "vulkan" : "gles"; if (backendProp == "vulkan") { } else { glExtra.depthBits = 24; // 24 :bits size glExtra.sharedContext = EGL_NO_CONTEXT; deviceCreateInfo.backendType = RENDER_NS::DeviceBackendType::OPENGLES; deviceCreateInfo.backendConfiguration = &glExtra; renderCreateInfo.applicationInfo = {}; renderCreateInfo.deviceCreateInfo = deviceCreateInfo; } auto rrc = engineInstance_.renderContext_->Init(renderCreateInfo); if (rrc != RENDER_NS::RenderResultCode::RENDER_SUCCESS) { WIDGET_LOGE("Failed to create render context"); return false; } engineInstance_.graphicsContext_.reset(CORE_NS::CreateInstance( *engineInstance_.renderContext_->GetInterface(), CORE3D_NS::UID_GRAPHICS_CONTEXT) .get()); if (!engineInstance_.graphicsContext_) { WIDGET_LOGE("create 3D context fail"); return false; } engineInstance_.graphicsContext_->Init(); WIDGET_LOGD("regester shader path"); static constexpr const RENDER_NS::IShaderManager::ShaderFilePathDesc desc{"shaders://"}; engineInstance_.engine_->GetFileManager().RegisterPath("shaders", "OhosRawFile://shaders", false); engineInstance_.renderContext_->GetDevice().GetShaderManager().LoadShaderFiles(desc); engineInstance_.engine_->GetFileManager().RegisterPath("appshaders", "OhosRawFile://shaders", false); static constexpr const RENDER_NS::IShaderManager::ShaderFilePathDesc desc1{"appshaders://"}; engineInstance_.renderContext_->GetDevice().GetShaderManager().LoadShaderFiles(desc1); WIDGET_LOGI("init engine success"); #ifdef SCENE_META_FUZZ auto &obr = META_NS::GetObjectRegistry(); // scene/meta // Save the stuff to the default object context. auto engineThread = META_NS::GetTaskQueueRegistry().GetTaskQueue(ENGINE_THREAD); // // this is the javascript thread... auto appThread = engineThread; auto doc = interface_cast(obr.GetDefaultObjectContext()); if (doc == nullptr) { WIDGET_LOGE("nullptr from interface_cast"); return false; } auto flags = META_NS::ObjectFlagBits::INTERNAL | META_NS::ObjectFlagBits::NATIVE; doc->AddProperty(META_NS::ConstructProperty("RenderContext", nullptr, flags)); doc->AddProperty(META_NS::ConstructProperty("EngineQueue", nullptr, flags)); doc->AddProperty(META_NS::ConstructProperty("AppQueue", nullptr, flags)); doc->AddProperty(META_NS::ConstructArrayProperty("Scenes", {}, flags)); doc->GetPropertyByName("EngineQueue")->SetValue(engineThread); doc->GetPropertyByName("AppQueue")->SetValue(appThread); doc->GetPropertyByName("RenderContext")->SetValue(engineInstance_.renderContext_); return false; }); engineThread->AddTask(engineInit); #endif return true; } void SceneInit::Deinit() { engineInstance_.graphicsContext_.reset(); engineInstance_.renderContext_->GetRenderer().RenderFrame({}); engineInstance_.renderContext_->GetDevice().WaitForIdle(); engineInstance_.renderContext_.reset(); #if SCENE_META_FUZZ const BASE_NS::Uid DefaultPluginList[]{SCENE_NS::UID_SCENE_PLUGIN}; #else const BASE_NS::Uid DefaultPluginList[]{RENDER_NS::UID_RENDER_PLUGIN, CORE3D_NS::UID_3D_PLUGIN}; #endif CORE_NS::GetPluginRegister().UnloadPlugins(DefaultPluginList); } SceneInit::~SceneInit() { Deinit(); } void SceneInit::DeinitRenderThread() { #if SCENE_META_FUZZ if (renderTask) { engineThread->CancelTask(renderTask); renderTask = nullptr; } auto engine_deinit = META_NS::MakeCallback([]() { // destroy all swapchains auto &obr = META_NS::GetObjectRegistry(); auto doc = interface_cast(obr.GetDefaultObjectContext()); if (doc == nullptr) { WIDGET_LOGE("nullptr from interface_cast"); return META_NS::IAny::Ptr{}; } // this is somewhat uncool { auto p3 = doc->GetPropertyByName("RenderContext"); doc->RemoveProperty(p3); auto p2 = doc->GetPropertyByName("AppQueue"); doc->RemoveProperty(p2); auto p1 = doc->GetPropertyByName("EngineQueue"); doc->RemoveProperty(p1); } doc->GetArrayPropertyByName("Scenes")->Reset(); return META_NS::IAny::Ptr{}; }); auto dummy = META_NS::MakeCallback([]() { return META_NS::IAny::Ptr{}; }); auto &tr = META_NS::GetTaskQueueRegistry(); if (releaseThread) { releaseThread->AddWaitableTask(dummy)->Wait(); tr.UnregisterTaskQueue(JS_RELEASE_THREAD); releaseThread.reset(); } if (ioThread) { ioThread->AddWaitableTask(dummy)->Wait(); tr.UnregisterTaskQueue(IO_QUEUE); ioThread.reset(); } if (engineThread) { engineThread->AddWaitableTask(engine_deinit)->Wait(); tr.UnregisterTaskQueue(ENGINE_THREAD); engineThread.reset(); } #endif CORE_LOG_E("unload E"); #if SCENE_META_FUZZ const BASE_NS::Uid DefaultPluginList[]{SCENE_NS::UID_SCENE_PLUGIN}; #else const BASE_NS::Uid DefaultPluginList[]{RENDER_NS::UID_RENDER_PLUGIN, CORE3D_NS::UID_3D_PLUGIN}; #endif CORE_NS::GetPluginRegister().UnloadPlugins(DefaultPluginList); CORE_LOG_E("unload X"); engineInstance_.renderContext_.reset(); engineInstance_.engine_.reset(); } std::shared_ptr SceneInit::CreateTextureLayer() { return {}; } bool SceneInit::LoadPluginsAndInit() { LockCompositor(); // an APP_FREEZE here, so add lock just in case, but suspect others' error WIDGET_LOGI("scene adapter loadPlugins"); if (hapInfo_.hapPath_ == "") { hapInfo_ = GetHapInfo(); } #define TO_STRING(name) #name #define PLATFORM_PATH_NAME(name) TO_STRING(name) CORE_NS::PlatformCreateInfo platformCreateInfo { PLATFORM_PATH_NAME(PLATFORM_CORE_ROOT_PATH), PLATFORM_PATH_NAME(PLATFORM_APP_ROOT_PATH), PLATFORM_PATH_NAME(PLATFORM_APP_PLUGIN_PATH), hapInfo_.hapPath_.c_str(), hapInfo_.bundleName_.c_str(), hapInfo_.moduleName_.c_str() }; #undef TO_STRING #undef PLATFORM_PATH_NAME if (!LoadPlugins(platformCreateInfo)) { WIDGET_LOGE("LoadPlugins failed"); UnlockCompositor(); return false; } if (!InitEngine(platformCreateInfo)) { WIDGET_LOGE("InitEngine failed"); UnlockCompositor(); return false; } CreateRenderFunction(); UnlockCompositor(); return true; } void SceneInit::OnWindowChange(const Render3D::WindowChangeInfo &windowChangeInfo) {} void SceneInit::CreateRenderFunction() {} void SceneInit::ShutdownPluginRegistry() { if (engineInstance_.libHandle_ == nullptr) { return ; } CORE_NS::GetPluginRegister = nullptr; CORE_NS::CreatePluginRegistry = nullptr; CORE_NS::IsDebugBuild = nullptr; CORE_NS::GetVersion = nullptr; } void SceneInit::RenderFunction() {} void SceneInit::RenderFrame(bool needsSyncPaint) {} std::shared_ptr CreateFuzzScene() { return std::make_shared(); } } // namespace OHOS::FUZZ