2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-extension/vector-animation-renderer/tizen-vector-animation-renderer.h>
22 #include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/object/property-array.h>
25 #include <tbm_surface_internal.h>
26 #include <cstring> // for strlen()
29 #include <dali-extension/vector-animation-renderer/tizen-vector-animation-manager.h>
31 // The plugin factories
32 extern "C" DALI_EXPORT_API Dali::VectorAnimationRendererPlugin* CreateVectorAnimationRendererPlugin(void)
34 return new Dali::Plugin::TizenVectorAnimationRenderer;
43 const char* const PIXEL_AREA_UNIFORM_NAME("pixelArea");
44 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
46 #if defined(DEBUG_ENABLED)
47 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION");
49 } // unnamed namespace
51 TizenVectorAnimationRenderer::TizenVectorAnimationRenderer()
61 mUploadCompletedSignal(),
70 mResourceReady(false),
71 mShaderChanged(false),
72 mResourceReadyTriggered(false)
74 TizenVectorAnimationManager::Get().AddEventHandler(*this);
77 TizenVectorAnimationRenderer::~TizenVectorAnimationRenderer()
79 Dali::Mutex::ScopedLock lock(mMutex);
82 DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "this = %p\n", this);
85 void TizenVectorAnimationRenderer::Finalize()
87 Dali::Mutex::ScopedLock lock(mMutex);
89 TizenVectorAnimationManager::Get().RemoveEventHandler(*this);
93 mRenderedTexture.Reset();
94 mPreviousTexture.Reset();
95 mVectorRenderer.reset();
97 mTargetSurface = nullptr;
100 mPropertyCallbacks.clear();
102 DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "[%p]\n", this);
105 bool TizenVectorAnimationRenderer::Load(const std::string& url)
107 Dali::Mutex::ScopedLock lock(mMutex);
111 mVectorRenderer = rlottie::Animation::loadFromFile(mUrl);
114 DALI_LOG_ERROR("Failed to load a Lottie file [%s] [%p]\n", mUrl.c_str(), this);
119 mTotalFrameNumber = static_cast<uint32_t>(mVectorRenderer->totalFrame());
120 mFrameRate = static_cast<float>(mVectorRenderer->frameRate());
123 mVectorRenderer->size(w, h);
124 mDefaultWidth = static_cast<uint32_t>(w);
125 mDefaultHeight = static_cast<uint32_t>(h);
127 DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "file [%s] [%p]\n", url.c_str(), this);
132 void TizenVectorAnimationRenderer::SetRenderer(Renderer renderer)
134 mRenderer = renderer;
135 mShaderChanged = false;
139 Dali::Mutex::ScopedLock lock(mMutex);
141 if(mResourceReady && mRenderedTexture)
143 TextureSet textureSet = renderer.GetTextures();
145 textureSet.SetTexture(0, mRenderedTexture);
147 mUploadCompletedSignal.Emit();
154 void TizenVectorAnimationRenderer::SetSize(uint32_t width, uint32_t height)
156 Dali::Mutex::ScopedLock lock(mMutex);
158 if(mWidth == width && mHeight == height)
160 DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Same size (%d, %d) [%p]\n", mWidth, mHeight, this);
166 DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Load is failed. Do not make texture [%p]\n", this);
170 mTargetSurface = NativeImageSourceQueue::New(width, height, NativeImageSourceQueue::ColorFormat::RGBA8888);
172 mTexture = Texture::New(*mTargetSurface);
179 mTbmQueue = AnyCast<tbm_surface_queue_h>(mTargetSurface->GetNativeImageSourceQueue());
184 mResourceReady = false;
186 // Reset the previous texture to destroy it in the main thread
187 mPreviousTexture.Reset();
189 DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "width = %d, height = %d [%p]\n", mWidth, mHeight, this);
192 bool TizenVectorAnimationRenderer::Render(uint32_t frameNumber)
194 Dali::Mutex::ScopedLock lock(mMutex);
196 if(!mTbmQueue || !mVectorRenderer || !mTargetSurface)
201 int canDequeue = tbm_surface_queue_can_dequeue(mTbmQueue, 0);
204 // Ignore the previous image which is inserted to the queue.
205 mTargetSurface->IgnoreSourceImage();
208 canDequeue = tbm_surface_queue_can_dequeue(mTbmQueue, 0);
215 tbm_surface_h tbmSurface;
217 if(tbm_surface_queue_dequeue(mTbmQueue, &tbmSurface) != TBM_SURFACE_QUEUE_ERROR_NONE)
219 DALI_LOG_ERROR("Failed to dequeue a tbm_surface [%p]\n", this);
223 tbm_surface_info_s info;
224 int ret = tbm_surface_map(tbmSurface, TBM_OPTION_WRITE, &info);
225 if(ret != TBM_SURFACE_ERROR_NONE)
227 DALI_LOG_ERROR("TizenVectorAnimationRenderer::Render: tbm_surface_map is failed! [%d] [%p]\n", ret, this);
228 tbm_surface_queue_cancel_dequeue(mTbmQueue, tbmSurface);
232 unsigned char* buffer = info.planes[0].ptr;
233 if(info.width != mWidth || info.height != mHeight || !buffer)
235 DALI_LOG_ERROR("TizenVectorAnimationRenderer::Render: Invalid tbm surface! [%d, %d, %p] [%p]\n", info.width, info.height, buffer, this);
236 tbm_surface_unmap(tbmSurface);
237 tbm_surface_queue_cancel_dequeue(mTbmQueue, tbmSurface);
241 rlottie::Surface surface;
242 bool existing = false;
246 // Need to reset buffer list
251 for(auto&& iter : mBuffers)
253 if(iter.first == tbmSurface)
255 // Find the buffer in the existing list
257 surface = iter.second;
265 tbm_surface_internal_ref(tbmSurface);
267 // Create Surface object
268 surface = rlottie::Surface(reinterpret_cast<uint32_t*>(buffer), mWidth, mHeight, static_cast<size_t>(info.planes[0].stride));
271 mBuffers.push_back(SurfacePair(tbmSurface, surface));
275 mVectorRenderer->renderSync(frameNumber, surface);
277 tbm_surface_unmap(tbmSurface);
279 tbm_surface_queue_enqueue(mTbmQueue, tbmSurface);
283 mPreviousTexture = mRenderedTexture; // It is used to destroy the object in the main thread.
284 mRenderedTexture = mTexture;
285 mResourceReady = true;
286 mResourceReadyTriggered = true;
288 TizenVectorAnimationManager::Get().TriggerEvent(*this);
290 DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Resource ready [current = %d] [%p]\n", frameNumber, this);
296 uint32_t TizenVectorAnimationRenderer::GetTotalFrameNumber() const
298 return mTotalFrameNumber;
301 float TizenVectorAnimationRenderer::GetFrameRate() const
306 void TizenVectorAnimationRenderer::GetDefaultSize(uint32_t& width, uint32_t& height) const
308 width = mDefaultWidth;
309 height = mDefaultHeight;
312 void TizenVectorAnimationRenderer::GetLayerInfo(Property::Map& map) const
314 Dali::Mutex::ScopedLock lock(mMutex);
318 auto layerInfo = mVectorRenderer->layers();
320 for(auto&& iter : layerInfo)
322 Property::Array frames;
323 frames.PushBack(std::get<1>(iter));
324 frames.PushBack(std::get<2>(iter));
325 map.Add(std::get<0>(iter), frames);
330 bool TizenVectorAnimationRenderer::GetMarkerInfo(const std::string& marker, uint32_t& startFrame, uint32_t& endFrame) const
332 Dali::Mutex::ScopedLock lock(mMutex);
336 auto markerList = mVectorRenderer->markers();
337 for(auto&& iter : markerList)
339 if(std::get<0>(iter).compare(marker) == 0)
341 startFrame = static_cast<uint32_t>(std::get<1>(iter));
342 endFrame = static_cast<uint32_t>(std::get<2>(iter));
350 void TizenVectorAnimationRenderer::InvalidateBuffer()
352 Dali::Mutex::ScopedLock lock(mMutex);
353 mResourceReady = false;
356 void TizenVectorAnimationRenderer::AddPropertyValueCallback(const std::string& keyPath, VectorProperty property, CallbackBase* callback, int32_t id)
358 Dali::Mutex::ScopedLock lock(mMutex);
360 mPropertyCallbacks.push_back(std::unique_ptr<CallbackBase>(callback));
364 case VectorProperty::FILL_COLOR:
366 mVectorRenderer->setValue<rlottie::Property::FillColor>(keyPath,
367 [property, callback, id](const rlottie::FrameInfo& info) {
368 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
372 return rlottie::Color(color.r, color.g, color.b);
374 return rlottie::Color(1.0f, 1.0f, 1.0f);
378 case VectorProperty::FILL_OPACITY:
380 mVectorRenderer->setValue<rlottie::Property::FillOpacity>(keyPath,
381 [property, callback, id](const rlottie::FrameInfo& info) {
382 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
384 if(value.Get(opacity))
386 return opacity * 100;
392 case VectorProperty::STROKE_COLOR:
394 mVectorRenderer->setValue<rlottie::Property::StrokeColor>(keyPath,
395 [property, callback, id](const rlottie::FrameInfo& info) {
396 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
400 return rlottie::Color(color.r, color.g, color.b);
402 return rlottie::Color(1.0f, 1.0f, 1.0f);
406 case VectorProperty::STROKE_OPACITY:
408 mVectorRenderer->setValue<rlottie::Property::StrokeOpacity>(keyPath,
409 [property, callback, id](const rlottie::FrameInfo& info) {
410 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
412 if(value.Get(opacity))
414 return opacity * 100;
420 case VectorProperty::STROKE_WIDTH:
422 mVectorRenderer->setValue<rlottie::Property::StrokeWidth>(keyPath,
423 [property, callback, id](const rlottie::FrameInfo& info) {
424 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
434 case VectorProperty::TRANSFORM_ANCHOR:
436 mVectorRenderer->setValue<rlottie::Property::TrAnchor>(keyPath,
437 [property, callback, id](const rlottie::FrameInfo& info) {
438 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
442 return rlottie::Point(point.x, point.y);
444 return rlottie::Point(0.0f, 0.0f);
448 case VectorProperty::TRANSFORM_POSITION:
450 mVectorRenderer->setValue<rlottie::Property::TrPosition>(keyPath,
451 [property, callback, id](const rlottie::FrameInfo& info) {
452 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
454 if(value.Get(position))
456 return rlottie::Point(position.x, position.y);
458 return rlottie::Point(0.0f, 0.0f);
462 case VectorProperty::TRANSFORM_SCALE:
464 mVectorRenderer->setValue<rlottie::Property::TrScale>(keyPath,
465 [property, callback, id](const rlottie::FrameInfo& info) {
466 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
470 return rlottie::Size(scale.x, scale.y);
472 return rlottie::Size(100.0f, 100.0f);
476 case VectorProperty::TRANSFORM_ROTATION:
478 mVectorRenderer->setValue<rlottie::Property::TrRotation>(keyPath,
479 [property, callback, id](const rlottie::FrameInfo& info) {
480 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
482 if(value.Get(rotation))
490 case VectorProperty::TRANSFORM_OPACITY:
492 mVectorRenderer->setValue<rlottie::Property::TrOpacity>(keyPath,
493 [property, callback, id](const rlottie::FrameInfo& info) {
494 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
496 if(value.Get(opacity))
498 return opacity * 100;
507 VectorAnimationRendererPlugin::UploadCompletedSignalType& TizenVectorAnimationRenderer::UploadCompletedSignal()
509 return mUploadCompletedSignal;
512 void TizenVectorAnimationRenderer::NotifyEvent()
514 Dali::Mutex::ScopedLock lock(mMutex);
516 if(mResourceReadyTriggered)
518 DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Set Texture [%p]\n", this);
521 if(mRenderer && mRenderedTexture)
523 TextureSet textureSet = mRenderer.GetTextures();
524 textureSet.SetTexture(0, mRenderedTexture);
527 mResourceReadyTriggered = false;
529 mUploadCompletedSignal.Emit();
532 mPreviousTexture.Reset();
535 void TizenVectorAnimationRenderer::SetShader()
542 Shader shader = mRenderer.GetShader();
544 std::string fragmentShader;
545 std::string vertexShader;
547 // Get the current fragment shader source
548 Property::Value program = shader.GetProperty(Shader::Property::PROGRAM);
549 Property::Map* map = program.GetMap();
552 Property::Value* fragment = map->Find("fragment");
555 fragmentShader = fragment->Get<std::string>();
558 Property::Value* vertex = map->Find("vertex");
561 vertexShader = vertex->Get<std::string>();
565 // Get custom fragment shader prefix
566 mTargetSurface->ApplyNativeFragmentShader(fragmentShader);
568 // Set the modified shader again
569 Shader newShader = Shader::New(vertexShader, fragmentShader);
570 newShader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
572 mRenderer.SetShader(newShader);
574 mShaderChanged = true;
577 void TizenVectorAnimationRenderer::ResetBuffers()
579 for(auto&& iter : mBuffers)
581 tbm_surface_internal_unref(iter.first);
586 } // namespace Plugin