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 "core/components_ng/pattern/model/model_adapter_wrapper.h"
17
18 #include <EGL/egl.h>
19 #include "foundation/graphic/graphic_3d/3d_widget_adapter/include/graphics_task.h"
20 #include "foundation/graphic/graphic_3d/3d_widget_adapter/include/ohos/graphics_manager.h"
21 #include "render_service_client/core/ui/rs_ui_director.h"
22 #include "render_service_client/core/ui/rs_ui_share_context.h"
23
24 namespace OHOS::Ace::NG {
25
ModelAdapterWrapper(uint32_t key)26 ModelAdapterWrapper::ModelAdapterWrapper(uint32_t key) : key_(key)
27 {
28 touchHandler_ = MakeRefPtr<ModelTouchHandler>();
29 touchHandler_->SetCameraEventCallback([weak = WeakClaim(this)]
30 (const OHOS::Render3D::SceneViewerTouchEvent& event) {
31 auto adapter = weak.Upgrade();
32 CHECK_NULL_VOID(adapter);
33 adapter->HandleCameraMove(event);
34 });
35
36 #if MULTI_ECS_UPDATE_AT_ONCE
37 RefPtr<PipelineBase> pipeline = PipelineBase::GetCurrentContext();
38 CHECK_NULL_VOID(pipeline);
39 if (pipeline) {
40 OHOS::Render3D::GraphicsManager::GetInstance().AttachContext(pipeline);
41 } else {
42 LOGE("MODEL_NG: pipeline context is null");
43 }
44 #endif
45 }
46
OnPaint(const RefPtr<ModelPaintProperty> & modelPaintProperty)47 void ModelAdapterWrapper::OnPaint(const RefPtr<ModelPaintProperty>& modelPaintProperty)
48 {
49 auto properties = ExtractPaintProperties(modelPaintProperty);
50 if (modelPaintProperty->NeedsCameraSetup()) {
51 UpdateCamera(properties);
52 }
53 if (modelPaintProperty->NeedsLightsSetup()) {
54 UpdateLights(properties);
55 }
56 if (modelPaintProperty->NeedsAnimationsSetup()) {
57 UpdateGLTFAnimations(properties);
58 }
59 if (modelPaintProperty->NeedsGeometriesSetup()) {
60 UpdateGeometries(properties);
61 }
62 if (modelPaintProperty->NeedsCustomRendersSetup()) {
63 UpdateCustomRenders(properties);
64 }
65 if (modelPaintProperty->NeedsShaderPathSetup()) {
66 UpdateShaderPath(properties);
67 }
68 if (modelPaintProperty->NeedsImageTexturePathsSetup()) {
69 UpdateImageTexturePaths(properties);
70 }
71 if (modelPaintProperty->NeedsShaderInputBuffersSetup()) {
72 UpdateShaderInputBuffers(properties);
73 }
74 DrawFrame();
75 }
76
UpdateCamera(const SceneViewerAdapterProperties & properties)77 void ModelAdapterWrapper::UpdateCamera(const SceneViewerAdapterProperties& properties)
78 {
79 LOGD("MODEL_NG: ModelAdapterWrapper::UpdateCamera()");
80 #if MULTI_ECS_UPDATE_AT_ONCE
81 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
82 #else
83 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
84 #endif
85 auto adapter = weak.Upgrade();
86 CHECK_NULL_VOID(adapter);
87 adapter->sceneViewerAdapter_->SetUpCameraTransform(properties.cameraPosition_, properties.cameraLookAt_,
88 properties.cameraUp_, properties.cameraRotation_);
89 adapter->sceneViewerAdapter_->SetUpCameraViewProjection(properties.zNear_, properties.zFar_, properties.fov_);
90 });
91 }
92
93 void ModelAdapterWrapper::UpdateLights(const SceneViewerAdapterProperties& properties)
94 {
95 LOGD("MODEL_NG: ModelAdapterWrapper::UpdateLights()");
96 if (!properties.lights_.empty()) {
97 #if MULTI_ECS_UPDATE_AT_ONCE
98 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
99 #else
100 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
101 #endif
102 auto adapter = weak.Upgrade();
103 CHECK_NULL_VOID(adapter);
104 adapter->sceneViewerAdapter_->AddLights(properties.lights_);
105 adapter->sceneViewerAdapter_->CreateLight();
106 });
107 }
108 }
109
110 void ModelAdapterWrapper::UpdateGLTFAnimations(const SceneViewerAdapterProperties& properties)
111 {
112 LOGD("MODEL_NG: ModelAdapterWrapper::UpdateGLTFAnimations() -> %zu", properties.animations_.size());
113 if (!properties.animations_.empty()) {
114 #if MULTI_ECS_UPDATE_AT_ONCE
115 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
116 #else
117 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
118 #endif
119 auto adapter = weak.Upgrade();
120 CHECK_NULL_VOID(adapter);
121 adapter->sceneViewerAdapter_->UpdateGLTFAnimations(properties.animations_);
122 });
123 }
124 }
125
126 void ModelAdapterWrapper::UpdateGeometries(const SceneViewerAdapterProperties& properties)
127 {
128 LOGD("MODEL_NG: ModelAdapterWrapper::UpdateGeometries() -> %zu", properties.geometries_.size());
129 if (!properties.geometries_.empty()) {
130 #if MULTI_ECS_UPDATE_AT_ONCE
131 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
132 #else
133 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
134 #endif
135 auto adapter = weak.Upgrade();
136 CHECK_NULL_VOID(adapter);
137 adapter->sceneViewerAdapter_->UpdateGeometries(properties.geometries_);
138 });
139 }
140 }
141
142 void ModelAdapterWrapper::DrawFrame()
143 {
144 ACE_FUNCTION_TRACE();
145 // if open MULTI_ECS_UPDATE_AT_ONCE macro SetGSVsyncCallback is called on current thread
146 // that means all the 3D engine task should be in syncorinize manner.
147 #if MULTI_ECS_UPDATE_AT_ONCE
148 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this)] {
149 #else
150 // Async painting does not seem to work.
151 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this)] {
152 #endif
153 auto adapter = weak.Upgrade();
154 CHECK_NULL_VOID(adapter);
155 adapter->sceneViewerAdapter_->DrawFrame();
156 });
157 }
158
159 void ModelAdapterWrapper::OnPaintFinish()
160 {
161 if (callback_) {
162 callback_();
163 }
164 }
165
166 SkDrawable* ModelAdapterWrapper::GetDrawable(OffsetF offset)
167 {
168 /*
169 Async painting does not seem to work.
170 */
171 CHECK_NULL_RETURN(textureLayer_, nullptr);
172 textureLayer_->SetOffset(offset.GetX(), offset.GetY());
173 ACE_FUNCTION_TRACE();
174
175 return textureLayer_.get();
176 }
177
178 std::shared_ptr<OHOS::Render3D::TextureLayer> ModelAdapterWrapper::GetTextureLayer(OffsetF offset)
179 {
180 textureLayer_->SetOffset(offset.GetX(), offset.GetY());
181 return textureLayer_;
182 }
183
184 void ModelAdapterWrapper::OnMeasureContent(const RefPtr<ModelLayoutProperty>& modelLayoutProperty, SizeF size)
185 {
186 LOGD("MODEL_NG: OnMeasureContent");
187 bool sizeChanged = size_.UpdateSizeWithCheck(size);
188 bool sceneChanged = modelLayoutProperty->NeedsSceneSetup();
189 bool needsSetup = !sceneIsSetUp_ || sceneChanged || sizeChanged;
190
191 if (IsInitialized() && sceneChanged) {
192 UnloadScene();
193 }
194
195 if (!IsInitialized()) {
196 Initialize();
197 }
198
199 if (!IsInitialized()) {
200 // Failed to create TextureLayer or Engine, or Cannot obtain EGL context
201 LOGW("MODEL_NG: OnMeasureContent() - Failed to initialize");
202 return;
203 }
204
205 if (sizeChanged) {
206 UpdateTextureLayer();
207 }
208
209 if (needsSetup) {
210 modelLayoutProperty->UpdateNeedsSceneSetup(false);
211 auto properties = ExtractLayoutProperties(modelLayoutProperty);
212 UpdateSceneViewerAdapter(properties);
213 }
214 }
215
216 void ModelAdapterWrapper::Initialize()
217 {
218 // Obtain EGLContext
219 EGLContext eglContext = GetRenderContext();
220
221 if (eglContext == EGL_NO_CONTEXT) {
222 LOGW("MODEL_NG: Initialize() - No render context. Start unify rendering");
223 }
224
225 CreateTextureLayer(eglContext);
226 CreateSceneViewerAdapter(eglContext_);
227 }
228
229 void ModelAdapterWrapper::CreateSceneViewerAdapter(const EGLContext& eglContext)
230 {
231 sceneViewerAdapter_ = std::make_shared<OHOS::Render3D::SceneViewerAdapter>(GetKey());
232 #if MULTI_ECS_UPDATE_AT_ONCE
233 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &eglContext] {
234 #else
235 // init engine in async manner sometimes crash on screen rotation
236 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &eglContext] {
237 #endif
238 auto adapter = weak.Upgrade();
239 CHECK_NULL_VOID(adapter);
240 auto& gfxManager = OHOS::Render3D::GraphicsManager::GetInstance();
241 auto &&engine = gfxManager.GetEngine(OHOS::Render3D::EngineFactory::EngineType::LUME, eglContext);
242 LOGD("MODEL_NG: ModelAdapterWrapper::CreateSceneViewerAdapter() init Engine key_ = %d", adapter->GetKey());
243 adapter->sceneViewerAdapter_->SetEngine(std::move(engine));
244 });
245 }
246
247 void ModelAdapterWrapper::UpdateSceneViewerAdapter(const SceneViewerAdapterProperties& properties)
248 {
249 #if MULTI_ECS_UPDATE_AT_ONCE
250 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
251 #else
252 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
253 #endif
254 auto adapter = weak.Upgrade();
255 CHECK_NULL_VOID(adapter);
256 const OHOS::Render3D::TextureInfo& obj = *(adapter->textureInfo_);
257 adapter->sceneViewerAdapter_->SetUpSceneViewer(
258 obj, properties.gltfSrc_, properties.backgroundSrc_, properties.bgType_);
259 LOGD("MODEL_NG: ModelAdapterWrapper::UpdateSceneViewerAdapter() glTFSrc_ %s GetKey() %d",
260 properties.gltfSrc_.c_str(), adapter->GetKey());
261 adapter->sceneIsSetUp_ = true;
262 });
263 }
264
265 void ModelAdapterWrapper::CreateTextureLayer(const EGLContext& eglContext)
266 {
267 // texture create must in sync manner
268 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &eglContext] {
269 auto adapter = weak.Upgrade();
270 CHECK_NULL_VOID(adapter);
271 auto& gfxManager = OHOS::Render3D::GraphicsManager::GetInstance();
272 gfxManager.Register(adapter->GetKey());
273
274 adapter->eglContext_ = gfxManager.CreateOffScreenContext(eglContext);
275 adapter->textureLayer_ = std::make_shared<OHOS::Render3D::TextureLayer>();
276 auto info = adapter->textureLayer_->CreateRenderTarget(adapter->size_.Width(), adapter->size_.Height());
277 adapter->textureInfo_ = std::make_shared<OHOS::Render3D::TextureInfo>(std::move(info));
278 adapter->textureLayer_->SetTextureInfo(info);
279 });
280 }
281
282 void ModelAdapterWrapper::UpdateTextureLayer()
283 {
284 CHECK_NULL_VOID(textureLayer_);
285 textureLayer_->SetWH(size_.Width(), size_.Height());
286 }
287
288 void ModelAdapterWrapper::UnloadScene()
289 {
290 #if MULTI_ECS_UPDATE_AT_ONCE
291 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this)] {
292 #else
293 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this)] {
294 #endif
295 auto adapter = weak.Upgrade();
296 CHECK_NULL_VOID(adapter);
297 adapter->sceneViewerAdapter_->UnLoadModel();
298 LOGD("MODEL_NG: UnloadScene -> Unload model GetKey() %d", adapter->GetKey());
299 });
300 }
301
302 SceneViewerAdapterProperties ModelAdapterWrapper::ExtractLayoutProperties(
303 const RefPtr<ModelLayoutProperty>& modelLayoutProperty)
304 {
305 SceneViewerAdapterProperties properties {};
306 properties.gltfSrc_ = modelLayoutProperty->GetModelSource().value_or(properties.gltfSrc_);
307 properties.backgroundSrc_ = modelLayoutProperty->GetModelBackground().value_or(properties.backgroundSrc_);
308 bool isTransparent = modelLayoutProperty->GetModelTransparent().value_or(false);
309 properties.bgType_ = isTransparent ? OHOS::Render3D::SceneViewerBackgroundType::TRANSPARENT :
310 OHOS::Render3D::SceneViewerBackgroundType::CUBE_MAP;
311
312 return properties;
313 }
314
315 SceneViewerAdapterProperties ModelAdapterWrapper::ExtractPaintProperties(
316 const RefPtr<ModelPaintProperty>& modelPaintProperty)
317 {
318 SceneViewerAdapterProperties properties {};
319
320 auto cameraPosition = modelPaintProperty->GetCameraPosition().value_or(properties.cameraPosition_.GetVec());
321 auto cameraDistance = modelPaintProperty->GetCameraDistance().value_or(properties.cameraPosition_.GetDistance());
322 auto cameraIsAngular = modelPaintProperty->GetCameraIsAngular().value_or(properties.cameraPosition_.GetIsAngular());
323 properties.cameraPosition_.SetVec(cameraPosition);
324 properties.cameraPosition_.SetDistance(cameraDistance);
325 properties.cameraPosition_.SetIsAngular(cameraIsAngular);
326 properties.cameraRotation_ = modelPaintProperty->GetCameraRotation().value_or(properties.cameraRotation_);
327 properties.cameraLookAt_ = modelPaintProperty->GetCameraLookAt().value_or(properties.cameraLookAt_);
328 properties.cameraUp_ = modelPaintProperty->GetCameraUp().value_or(properties.cameraUp_);
329 properties.zNear_ = modelPaintProperty->GetCameraZNear().value_or(properties.zNear_);
330 properties.zFar_ = modelPaintProperty->GetCameraZFar().value_or(properties.zFar_);
331 properties.fov_ = modelPaintProperty->GetCameraFOV().value_or(properties.fov_);
332 properties.lights_ = modelPaintProperty->GetModelLights().value_or(properties.lights_);
333 properties.animations_ = modelPaintProperty->GetModelAnimations().value_or(properties.animations_);
334 properties.geometries_ = modelPaintProperty->GetModelGeometries().value_or(properties.geometries_);
335 properties.customRenders_ = modelPaintProperty->GetModelCustomRenders().value_or(properties.customRenders_);
336 properties.shaderPath_ = modelPaintProperty->GetShaderPath().value_or(properties.shaderPath_);
337 properties.imageTexturePaths_ =
338 modelPaintProperty->GetModelImageTexturePaths().value_or(properties.imageTexturePaths_);
339 properties.shaderInputBuffers_ =
340 modelPaintProperty->GetModelShaderInputBuffers().value_or(properties.shaderInputBuffers_);
341 return properties;
342 }
343
344 EGLContext ModelAdapterWrapper::GetRenderContext()
345 {
346 auto ret = EGL_NO_CONTEXT;
347 ret = Rosen::RSUIShareContext::GetInstance().GetRsRenderContext();
348 return ret;
349 }
350
351 bool ModelAdapterWrapper::IsInitialized()
352 {
353 return sceneViewerAdapter_ ? true : false;
354 }
355
356 bool ModelAdapterWrapper::IsReady()
357 {
358 return IsInitialized() && sceneIsSetUp_;
359 }
360
361 bool ModelAdapterWrapper::NeedsRepaint()
362 {
363 if (!sceneViewerAdapter_) {
364 return false;
365 }
366
367 if (sceneViewerAdapter_->IsAnimating() || sceneViewerAdapter_->HandlesNotReady()) {
368 return true;
369 }
370
371 return needsRepaint_;
372 }
373
374 uint32_t ModelAdapterWrapper::GetKey()
375 {
376 return key_;
377 }
378
379 void ModelAdapterWrapper::SetPaintFinishCallback(PaintFinishCallback callback)
380 {
381 callback_ = std::move(callback);
382 }
383
384 bool ModelAdapterWrapper::HandleTouchEvent(const TouchEventInfo& info)
385 {
386 CHECK_NULL_RETURN(touchHandler_, false);
387 return touchHandler_->HandleTouchEvent(info);
388 }
389
390 void ModelAdapterWrapper::HandleCameraMove(const OHOS::Render3D::SceneViewerTouchEvent& event)
391 {
392 LOGD("MODEL_NG HandleCameraMove() eventId[%d], eventType[%zu], position[%.2f, %.2f], delta[%.2f, %.2f], key = %d",
393 event.GetFingerId(), event.GetEventType(), event.GetGlobalLocation().GetX(), event.GetGlobalLocation().GetY(),
394 event.GetDeltaChange().GetX(), event.GetDeltaChange().GetY(), GetKey());
395 #if MULTI_ECS_UPDATE_AT_ONCE
396 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &event] {
397 #else
398 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &event] {
399 #endif
400 auto adapter = weak.Upgrade();
401 CHECK_NULL_VOID(adapter);
402 adapter->sceneViewerAdapter_->OnTouchEvent(event);
403 });
404 }
405
406 void ModelAdapterWrapper::UpdateCustomRenders(const SceneViewerAdapterProperties& properties)
407 {
408 LOGD("MODEL_NG: ModelAdapterWrapper::UpdateCustomRenders() size: %zu", properties.customRenders_.size());
409 if (!properties.customRenders_.empty()) {
410 #if MULTI_ECS_UPDATE_AT_ONCE
411 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
412 #else
413 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
414 #endif
415 auto adapter = weak.Upgrade();
416 CHECK_NULL_VOID(adapter);
417 adapter->sceneViewerAdapter_->AddCustomRenders(properties.customRenders_);
418 });
419 }
420 }
421
422 void ModelAdapterWrapper::UpdateShaderPath(const SceneViewerAdapterProperties& properties)
423 {
424 LOGD("ModelAdapterWrapper::UpdateShaderPath() %s", properties.shaderPath_.c_str());
425 #if MULTI_ECS_UPDATE_AT_ONCE
426 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
427 #else
428 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
429 #endif
430 auto adapter = weak.Upgrade();
431 CHECK_NULL_VOID(adapter);
432 adapter->sceneViewerAdapter_->UpdateShaderPath(properties.shaderPath_);
433 });
434 }
435
436 void ModelAdapterWrapper::UpdateImageTexturePaths(const SceneViewerAdapterProperties& properties)
437 {
438 LOGD("MODEL_NG: ModelAdapterWrapper::UpdateImageTexturePaths() size: %zu", properties.imageTexturePaths_.size());
439 if (!properties.imageTexturePaths_.empty()) {
440 #if MULTI_ECS_UPDATE_AT_ONCE
441 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
442 #else
443 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
444 #endif
445 auto adapter = weak.Upgrade();
446 CHECK_NULL_VOID(adapter);
447 adapter->sceneViewerAdapter_->UpdateImageTexturePaths(properties.imageTexturePaths_);
448 });
449 }
450 }
451
452 void ModelAdapterWrapper::UpdateShaderInputBuffers(const SceneViewerAdapterProperties& properties)
453 {
454 LOGD("MODEL_NG: ModelAdapterWrapper::UpdateShaderInputBuffers() size: %zu", properties.shaderInputBuffers_.size());
455 if (!properties.shaderInputBuffers_.empty()) {
456 #if MULTI_ECS_UPDATE_AT_ONCE
457 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
458 #else
459 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &properties] {
460 #endif
461 auto adapter = weak.Upgrade();
462 CHECK_NULL_VOID(adapter);
463 adapter->sceneViewerAdapter_->UpdateShaderInputBuffers(properties.shaderInputBuffers_);
464 });
465 }
466 }
467
468 } // namespace OHOS::Ace::NG
469