bec6d149e2f7561cfc886b03427b53d672074d87
[platform/core/uifw/dali-extension.git] / dali-extension / vector-animation-renderer / tizen-vector-animation-renderer.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-extension/vector-animation-renderer/tizen-vector-animation-renderer.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
23 #include <dali/devel-api/common/hash.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/object/property-array.h>
26 #include <tbm_surface_internal.h>
27 #include <cstring> // for strlen()
28
29 // INTERNAL INCLUDES
30 #include <dali-extension/vector-animation-renderer/tizen-vector-animation-manager.h>
31
32 // The plugin factories
33 extern "C" DALI_EXPORT_API Dali::VectorAnimationRendererPlugin* CreateVectorAnimationRendererPlugin(void)
34 {
35   return new Dali::Plugin::TizenVectorAnimationRenderer;
36 }
37
38 namespace Dali
39 {
40 namespace Plugin
41 {
42 namespace
43 {
44 const char* const PIXEL_AREA_UNIFORM_NAME("pixelArea");
45 const Vector4     FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
46
47 #if defined(DEBUG_ENABLED)
48 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION");
49 #endif
50 } // unnamed namespace
51
52 TizenVectorAnimationRenderer::TizenVectorAnimationRenderer()
53 : mUrl(),
54   mBuffers(),
55   mMutex(),
56   mRenderer(),
57   mTexture(),
58   mRenderedTexture(),
59   mPreviousTexture(),
60   mTargetSurface(),
61   mVectorRenderer(),
62   mUploadCompletedSignal(),
63   mTbmQueue(NULL),
64   mTotalFrameNumber(0),
65   mWidth(0),
66   mHeight(0),
67   mDefaultWidth(0),
68   mDefaultHeight(0),
69   mFrameRate(60.0f),
70   mLoadFailed(false),
71   mResourceReady(false),
72   mShaderChanged(false),
73   mResourceReadyTriggered(false)
74 {
75   TizenVectorAnimationManager::Get().AddEventHandler(*this);
76 }
77
78 TizenVectorAnimationRenderer::~TizenVectorAnimationRenderer()
79 {
80   Dali::Mutex::ScopedLock lock(mMutex);
81
82   ResetBuffers();
83   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "this = %p\n", this);
84 }
85
86 void TizenVectorAnimationRenderer::Finalize()
87 {
88   Dali::Mutex::ScopedLock lock(mMutex);
89
90   TizenVectorAnimationManager::Get().RemoveEventHandler(*this);
91
92   mRenderer.Reset();
93   mTexture.Reset();
94   mRenderedTexture.Reset();
95   mPreviousTexture.Reset();
96   mVectorRenderer.reset();
97
98   mTargetSurface = nullptr;
99   mTbmQueue      = NULL;
100
101   mPropertyCallbacks.clear();
102
103   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "[%p]\n", this);
104 }
105
106 bool TizenVectorAnimationRenderer::Load(const std::string& url)
107 {
108   Dali::Mutex::ScopedLock lock(mMutex);
109
110   mUrl = url;
111
112   mVectorRenderer = rlottie::Animation::loadFromFile(mUrl);
113   if(!mVectorRenderer)
114   {
115     DALI_LOG_ERROR("Failed to load a Lottie file [%s] [%p]\n", mUrl.c_str(), this);
116     mLoadFailed = true;
117     return false;
118   }
119
120   mTotalFrameNumber = static_cast<uint32_t>(mVectorRenderer->totalFrame());
121   mFrameRate        = static_cast<float>(mVectorRenderer->frameRate());
122
123   size_t w, h;
124   mVectorRenderer->size(w, h);
125   mDefaultWidth  = static_cast<uint32_t>(w);
126   mDefaultHeight = static_cast<uint32_t>(h);
127
128   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "file [%s] [%p]\n", url.c_str(), this);
129
130   return true;
131 }
132
133 bool TizenVectorAnimationRenderer::Load(const Dali::Vector<uint8_t>& data)
134 {
135   Dali::Mutex::ScopedLock lock(mMutex);
136
137   std::string jsonData(data.Begin(), data.End());    ///< Convert from raw buffer to string.
138   auto        hashValue = Dali::CalculateHash(data); ///< Will be used for rlottie internal cache system.
139
140   mVectorRenderer = rlottie::Animation::loadFromData(std::move(jsonData), std::to_string(hashValue));
141   if(!mVectorRenderer)
142   {
143     DALI_LOG_ERROR("Failed to load a Lottie data [data size : %zu byte] [%p]\n", data.Size(), this);
144     mLoadFailed = true;
145     return false;
146   }
147
148   mTotalFrameNumber = static_cast<uint32_t>(mVectorRenderer->totalFrame());
149   mFrameRate        = static_cast<float>(mVectorRenderer->frameRate());
150
151   size_t w, h;
152   mVectorRenderer->size(w, h);
153   mDefaultWidth  = static_cast<uint32_t>(w);
154   mDefaultHeight = static_cast<uint32_t>(h);
155
156   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "data [data size : %zu byte] [%p]\n", data.Size(), this);
157
158   return true;
159 }
160
161 void TizenVectorAnimationRenderer::SetRenderer(Renderer renderer)
162 {
163   mRenderer      = renderer;
164   mShaderChanged = false;
165
166   if(mTargetSurface)
167   {
168     Dali::Mutex::ScopedLock lock(mMutex);
169
170     if(mResourceReady && mRenderedTexture)
171     {
172       TextureSet textureSet = renderer.GetTextures();
173
174       textureSet.SetTexture(0, mRenderedTexture);
175
176       mUploadCompletedSignal.Emit();
177     }
178
179     SetShader();
180   }
181 }
182
183 void TizenVectorAnimationRenderer::SetSize(uint32_t width, uint32_t height)
184 {
185   Dali::Mutex::ScopedLock lock(mMutex);
186
187   if(mWidth == width && mHeight == height)
188   {
189     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Same size (%d, %d) [%p]\n", mWidth, mHeight, this);
190     return;
191   }
192
193   if(mLoadFailed)
194   {
195     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Load is failed. Do not make texture [%p]\n", this);
196     return;
197   }
198
199   mTargetSurface = NativeImageSourceQueue::New(width, height, NativeImageSourceQueue::ColorFormat::RGBA8888);
200
201   mTexture = Texture::New(*mTargetSurface);
202
203   if(mRenderer)
204   {
205     SetShader();
206   }
207
208   mTbmQueue = AnyCast<tbm_surface_queue_h>(mTargetSurface->GetNativeImageSourceQueue());
209
210   mWidth  = width;
211   mHeight = height;
212
213   mResourceReady = false;
214
215   // Reset the previous texture to destroy it in the main thread
216   mPreviousTexture.Reset();
217
218   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "width = %d, height = %d [%p]\n", mWidth, mHeight, this);
219 }
220
221 bool TizenVectorAnimationRenderer::Render(uint32_t frameNumber)
222 {
223   Dali::Mutex::ScopedLock lock(mMutex);
224
225   if(!mTbmQueue || !mVectorRenderer || !mTargetSurface)
226   {
227     return false;
228   }
229
230   int canDequeue = tbm_surface_queue_can_dequeue(mTbmQueue, 0);
231   if(!canDequeue)
232   {
233     // Ignore the previous image which is inserted to the queue.
234     mTargetSurface->IgnoreSourceImage();
235
236     // Check again
237     canDequeue = tbm_surface_queue_can_dequeue(mTbmQueue, 0);
238     if(!canDequeue)
239     {
240       return false;
241     }
242   }
243
244   tbm_surface_h tbmSurface;
245
246   if(tbm_surface_queue_dequeue(mTbmQueue, &tbmSurface) != TBM_SURFACE_QUEUE_ERROR_NONE)
247   {
248     DALI_LOG_ERROR("Failed to dequeue a tbm_surface [%p]\n", this);
249     return false;
250   }
251
252   tbm_surface_info_s info;
253   int                ret = tbm_surface_map(tbmSurface, TBM_OPTION_WRITE, &info);
254   if(ret != TBM_SURFACE_ERROR_NONE)
255   {
256     DALI_LOG_ERROR("TizenVectorAnimationRenderer::Render: tbm_surface_map is failed! [%d] [%p]\n", ret, this);
257     tbm_surface_queue_cancel_dequeue(mTbmQueue, tbmSurface);
258     return false;
259   }
260
261   unsigned char* buffer = info.planes[0].ptr;
262   if(info.width != mWidth || info.height != mHeight || !buffer)
263   {
264     DALI_LOG_ERROR("TizenVectorAnimationRenderer::Render: Invalid tbm surface! [%d, %d, %p] [%p]\n", info.width, info.height, buffer, this);
265     tbm_surface_unmap(tbmSurface);
266     tbm_surface_queue_cancel_dequeue(mTbmQueue, tbmSurface);
267     return false;
268   }
269
270   rlottie::Surface surface;
271   bool             existing = false;
272
273   if(!mResourceReady)
274   {
275     // Need to reset buffer list
276     ResetBuffers();
277   }
278   else
279   {
280     for(auto&& iter : mBuffers)
281     {
282       if(iter.first == tbmSurface)
283       {
284         // Find the buffer in the existing list
285         existing = true;
286         surface  = iter.second;
287         break;
288       }
289     }
290   }
291
292   if(!existing)
293   {
294     tbm_surface_internal_ref(tbmSurface);
295
296     // Create Surface object
297     surface = rlottie::Surface(reinterpret_cast<uint32_t*>(buffer), mWidth, mHeight, static_cast<size_t>(info.planes[0].stride));
298
299     // Push the buffer
300     mBuffers.push_back(SurfacePair(tbmSurface, surface));
301   }
302
303   // Render the frame
304   mVectorRenderer->renderSync(frameNumber, surface);
305
306   tbm_surface_unmap(tbmSurface);
307
308   tbm_surface_queue_enqueue(mTbmQueue, tbmSurface);
309
310   if(!mResourceReady)
311   {
312     mPreviousTexture        = mRenderedTexture; // It is used to destroy the object in the main thread.
313     mRenderedTexture        = mTexture;
314     mResourceReady          = true;
315     mResourceReadyTriggered = true;
316
317     TizenVectorAnimationManager::Get().TriggerEvent(*this);
318
319     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Resource ready [current = %d] [%p]\n", frameNumber, this);
320   }
321
322   return true;
323 }
324
325 void TizenVectorAnimationRenderer::RenderStopped()
326 {
327   if(mTargetSurface)
328   {
329     // Animation is stopped. Free empty buffers
330     mTargetSurface->FreeReleasedBuffers();
331
332     {
333       Dali::Mutex::ScopedLock lock(mMutex);
334       ResetBuffers();
335     }
336   }
337 }
338
339 uint32_t TizenVectorAnimationRenderer::GetTotalFrameNumber() const
340 {
341   return mTotalFrameNumber;
342 }
343
344 float TizenVectorAnimationRenderer::GetFrameRate() const
345 {
346   return mFrameRate;
347 }
348
349 void TizenVectorAnimationRenderer::GetDefaultSize(uint32_t& width, uint32_t& height) const
350 {
351   width  = mDefaultWidth;
352   height = mDefaultHeight;
353 }
354
355 void TizenVectorAnimationRenderer::GetLayerInfo(Property::Map& map) const
356 {
357   Dali::Mutex::ScopedLock lock(mMutex);
358
359   if(mVectorRenderer)
360   {
361     auto layerInfo = mVectorRenderer->layers();
362
363     for(auto&& iter : layerInfo)
364     {
365       Property::Array frames;
366       frames.PushBack(std::get<1>(iter));
367       frames.PushBack(std::get<2>(iter));
368       map.Add(std::get<0>(iter), frames);
369     }
370   }
371 }
372
373 bool TizenVectorAnimationRenderer::GetMarkerInfo(const std::string& marker, uint32_t& startFrame, uint32_t& endFrame) const
374 {
375   Dali::Mutex::ScopedLock lock(mMutex);
376
377   if(mVectorRenderer)
378   {
379     auto markerList = mVectorRenderer->markers();
380     for(auto&& iter : markerList)
381     {
382       if(std::get<0>(iter).compare(marker) == 0)
383       {
384         startFrame = static_cast<uint32_t>(std::get<1>(iter));
385         endFrame   = static_cast<uint32_t>(std::get<2>(iter));
386         return true;
387       }
388     }
389   }
390   return false;
391 }
392
393 void TizenVectorAnimationRenderer::InvalidateBuffer()
394 {
395   Dali::Mutex::ScopedLock lock(mMutex);
396   mResourceReady = false;
397 }
398
399 void TizenVectorAnimationRenderer::AddPropertyValueCallback(const std::string& keyPath, VectorProperty property, CallbackBase* callback, int32_t id)
400 {
401   Dali::Mutex::ScopedLock lock(mMutex);
402
403   mPropertyCallbacks.push_back(std::unique_ptr<CallbackBase>(callback));
404
405   switch(property)
406   {
407     case VectorProperty::FILL_COLOR:
408     {
409       mVectorRenderer->setValue<rlottie::Property::FillColor>(keyPath,
410                                                               [property, callback, id](const rlottie::FrameInfo& info) {
411                                                                 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
412                                                                 Vector3         color;
413                                                                 if(value.Get(color))
414                                                                 {
415                                                                   return rlottie::Color(color.r, color.g, color.b);
416                                                                 }
417                                                                 return rlottie::Color(1.0f, 1.0f, 1.0f);
418                                                               });
419       break;
420     }
421     case VectorProperty::FILL_OPACITY:
422     {
423       mVectorRenderer->setValue<rlottie::Property::FillOpacity>(keyPath,
424                                                                 [property, callback, id](const rlottie::FrameInfo& info) {
425                                                                   Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
426                                                                   float           opacity;
427                                                                   if(value.Get(opacity))
428                                                                   {
429                                                                     return opacity * 100;
430                                                                   }
431                                                                   return 100.0f;
432                                                                 });
433       break;
434     }
435     case VectorProperty::STROKE_COLOR:
436     {
437       mVectorRenderer->setValue<rlottie::Property::StrokeColor>(keyPath,
438                                                                 [property, callback, id](const rlottie::FrameInfo& info) {
439                                                                   Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
440                                                                   Vector3         color;
441                                                                   if(value.Get(color))
442                                                                   {
443                                                                     return rlottie::Color(color.r, color.g, color.b);
444                                                                   }
445                                                                   return rlottie::Color(1.0f, 1.0f, 1.0f);
446                                                                 });
447       break;
448     }
449     case VectorProperty::STROKE_OPACITY:
450     {
451       mVectorRenderer->setValue<rlottie::Property::StrokeOpacity>(keyPath,
452                                                                   [property, callback, id](const rlottie::FrameInfo& info) {
453                                                                     Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
454                                                                     float           opacity;
455                                                                     if(value.Get(opacity))
456                                                                     {
457                                                                       return opacity * 100;
458                                                                     }
459                                                                     return 100.0f;
460                                                                   });
461       break;
462     }
463     case VectorProperty::STROKE_WIDTH:
464     {
465       mVectorRenderer->setValue<rlottie::Property::StrokeWidth>(keyPath,
466                                                                 [property, callback, id](const rlottie::FrameInfo& info) {
467                                                                   Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
468                                                                   float           width;
469                                                                   if(value.Get(width))
470                                                                   {
471                                                                     return width;
472                                                                   }
473                                                                   return 1.0f;
474                                                                 });
475       break;
476     }
477     case VectorProperty::TRANSFORM_ANCHOR:
478     {
479       mVectorRenderer->setValue<rlottie::Property::TrAnchor>(keyPath,
480                                                              [property, callback, id](const rlottie::FrameInfo& info) {
481                                                                Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
482                                                                Vector2         point;
483                                                                if(value.Get(point))
484                                                                {
485                                                                  return rlottie::Point(point.x, point.y);
486                                                                }
487                                                                return rlottie::Point(0.0f, 0.0f);
488                                                              });
489       break;
490     }
491     case VectorProperty::TRANSFORM_POSITION:
492     {
493       mVectorRenderer->setValue<rlottie::Property::TrPosition>(keyPath,
494                                                                [property, callback, id](const rlottie::FrameInfo& info) {
495                                                                  Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
496                                                                  Vector2         position;
497                                                                  if(value.Get(position))
498                                                                  {
499                                                                    return rlottie::Point(position.x, position.y);
500                                                                  }
501                                                                  return rlottie::Point(0.0f, 0.0f);
502                                                                });
503       break;
504     }
505     case VectorProperty::TRANSFORM_SCALE:
506     {
507       mVectorRenderer->setValue<rlottie::Property::TrScale>(keyPath,
508                                                             [property, callback, id](const rlottie::FrameInfo& info) {
509                                                               Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
510                                                               Vector2         scale;
511                                                               if(value.Get(scale))
512                                                               {
513                                                                 return rlottie::Size(scale.x, scale.y);
514                                                               }
515                                                               return rlottie::Size(100.0f, 100.0f);
516                                                             });
517       break;
518     }
519     case VectorProperty::TRANSFORM_ROTATION:
520     {
521       mVectorRenderer->setValue<rlottie::Property::TrRotation>(keyPath,
522                                                                [property, callback, id](const rlottie::FrameInfo& info) {
523                                                                  Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
524                                                                  float           rotation;
525                                                                  if(value.Get(rotation))
526                                                                  {
527                                                                    return rotation;
528                                                                  }
529                                                                  return 0.0f;
530                                                                });
531       break;
532     }
533     case VectorProperty::TRANSFORM_OPACITY:
534     {
535       mVectorRenderer->setValue<rlottie::Property::TrOpacity>(keyPath,
536                                                               [property, callback, id](const rlottie::FrameInfo& info) {
537                                                                 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
538                                                                 float           opacity;
539                                                                 if(value.Get(opacity))
540                                                                 {
541                                                                   return opacity * 100;
542                                                                 }
543                                                                 return 100.0f;
544                                                               });
545       break;
546     }
547   }
548 }
549
550 VectorAnimationRendererPlugin::UploadCompletedSignalType& TizenVectorAnimationRenderer::UploadCompletedSignal()
551 {
552   return mUploadCompletedSignal;
553 }
554
555 void TizenVectorAnimationRenderer::NotifyEvent()
556 {
557   bool emitSignal = false;
558   {
559     Dali::Mutex::ScopedLock lock(mMutex);
560
561     if(mResourceReadyTriggered)
562     {
563       DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Set Texture [%p]\n", this);
564
565       // Set texture
566       if(mRenderer && mRenderedTexture)
567       {
568         TextureSet textureSet = mRenderer.GetTextures();
569         textureSet.SetTexture(0, mRenderedTexture);
570       }
571
572       mResourceReadyTriggered = false;
573       emitSignal              = true;
574     }
575
576     mPreviousTexture.Reset();
577   }
578   if(emitSignal)
579   {
580     mUploadCompletedSignal.Emit();
581   }
582 }
583
584 void TizenVectorAnimationRenderer::SetShader()
585 {
586   if(mShaderChanged)
587   {
588     return;
589   }
590
591   Shader shader = mRenderer.GetShader();
592
593   std::string fragmentShader;
594   std::string vertexShader;
595
596   // Get the current fragment shader source
597   Property::Value program = shader.GetProperty(Shader::Property::PROGRAM);
598   Property::Map*  map     = program.GetMap();
599   if(map)
600   {
601     Property::Value* fragment = map->Find("fragment");
602     if(fragment)
603     {
604       fragmentShader = fragment->Get<std::string>();
605     }
606
607     Property::Value* vertex = map->Find("vertex");
608     if(vertex)
609     {
610       vertexShader = vertex->Get<std::string>();
611     }
612   }
613
614   // Get custom fragment shader prefix
615   mTargetSurface->ApplyNativeFragmentShader(fragmentShader);
616
617   // Set the modified shader again
618   Shader newShader = Shader::New(vertexShader, fragmentShader);
619   newShader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
620
621   mRenderer.SetShader(newShader);
622
623   mShaderChanged = true;
624 }
625
626 void TizenVectorAnimationRenderer::ResetBuffers()
627 {
628   for(auto&& iter : mBuffers)
629   {
630     tbm_surface_internal_unref(iter.first);
631   }
632   mBuffers.clear();
633 }
634
635 } // namespace Plugin
636
637 } // namespace Dali