2 * Copyright (c) 2019 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/public-api/object/property-array.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
25 #include <cstring> // for strlen()
26 #include <tbm_surface_internal.h>
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;
46 const char* const DEFAULT_SAMPLER_TYPENAME( "sampler2D" );
47 const char* const PIXEL_AREA_UNIFORM_NAME( "pixelArea" );
49 const Vector4 FULL_TEXTURE_RECT( 0.f, 0.f, 1.f, 1.f );
51 } // unnamed namespace
53 TizenVectorAnimationRenderer::TizenVectorAnimationRenderer()
63 mUploadCompletedSignal(),
65 mTotalFrameNumber( 0 ),
71 mResourceReady( false ),
72 mShaderChanged( false ),
73 mResourceReadyTriggered( false )
77 TizenVectorAnimationRenderer::~TizenVectorAnimationRenderer()
79 Dali::Mutex::ScopedLock lock( mMutex );
82 DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::~TizenVectorAnimationRenderer: this = %p\n", this );
85 bool TizenVectorAnimationRenderer::Initialize( const std::string& url )
89 mVectorRenderer = rlottie::Animation::loadFromFile( mUrl );
90 if( !mVectorRenderer )
92 DALI_LOG_ERROR( "Failed to load a Lottie file [%s] [%p]\n", mUrl.c_str(), this );
96 mTotalFrameNumber = mVectorRenderer->totalFrame();
97 mFrameRate = static_cast< float >( mVectorRenderer->frameRate() );
100 mVectorRenderer->size( w, h );
101 mDefaultWidth = static_cast< uint32_t >( w );
102 mDefaultHeight = static_cast< uint32_t >( h );
104 TizenVectorAnimationManager::Get().AddEventHandler( *this );
106 DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::Initialize: file [%s] [%p]\n", url.c_str(), this );
111 void TizenVectorAnimationRenderer::Finalize()
113 Dali::Mutex::ScopedLock lock( mMutex );
115 TizenVectorAnimationManager::Get().RemoveEventHandler( *this );
119 mRenderedTexture.Reset();
120 mPreviousTexture.Reset();
121 mVectorRenderer.reset();
123 mTargetSurface = nullptr;
126 DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::Finalize: [%p]\n", this );
129 void TizenVectorAnimationRenderer::SetRenderer( Renderer renderer )
131 mRenderer = renderer;
132 mShaderChanged = false;
136 Dali::Mutex::ScopedLock lock( mMutex );
138 if( mResourceReady && mRenderedTexture )
140 TextureSet textureSet = renderer.GetTextures();
142 textureSet.SetTexture( 0, mRenderedTexture );
144 mUploadCompletedSignal.Emit();
151 void TizenVectorAnimationRenderer::SetSize( uint32_t width, uint32_t height )
153 Dali::Mutex::ScopedLock lock( mMutex );
155 if( mWidth == width && mHeight == height )
157 DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::SetSize: Same size (%d, %d) [%p]\n", mWidth, mHeight, this );
161 mTargetSurface = NativeImageSourceQueue::New( width, height, NativeImageSourceQueue::COLOR_DEPTH_DEFAULT );
163 mTexture = Texture::New( *mTargetSurface );
170 mTbmQueue = AnyCast< tbm_surface_queue_h >( mTargetSurface->GetNativeImageSourceQueue() );
175 mResourceReady = false;
177 // Reset the previous texture to destroy it in the main thread
178 mPreviousTexture.Reset();
180 DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::SetSize: width = %d, height = %d [%p]\n", mWidth, mHeight, this );
183 bool TizenVectorAnimationRenderer::Render( uint32_t frameNumber )
185 Dali::Mutex::ScopedLock lock( mMutex );
187 if( !mTbmQueue || !mVectorRenderer || !mTargetSurface )
192 int canDequeue = tbm_surface_queue_can_dequeue( mTbmQueue, 0 );
195 // Ignore the previous image which is inserted to the queue.
196 mTargetSurface->IgnoreSourceImage();
199 canDequeue = tbm_surface_queue_can_dequeue( mTbmQueue, 0 );
206 tbm_surface_h tbmSurface;
208 if( tbm_surface_queue_dequeue( mTbmQueue, &tbmSurface ) != TBM_SURFACE_QUEUE_ERROR_NONE )
210 DALI_LOG_ERROR( "Failed to dequeue a tbm_surface [%p]\n", this );
214 tbm_surface_info_s info;
215 tbm_surface_map( tbmSurface, TBM_OPTION_WRITE, &info );
217 rlottie::Surface surface;
218 bool existing = false;
220 if( !mResourceReady )
222 // Need to reset buffer list
227 for( auto&& iter : mBuffers )
229 if( iter.first == tbmSurface )
231 // Find the buffer in the existing list
233 surface = iter.second;
241 unsigned char* buffer = info.planes[0].ptr;
244 DALI_LOG_ERROR( "TizenVectorAnimationRenderer::Render: tbm buffer pointer is null! [%p]\n", this );
245 tbm_surface_unmap( tbmSurface );
249 tbm_surface_internal_ref( tbmSurface );
251 // Create Surface object
252 surface = rlottie::Surface( reinterpret_cast< uint32_t* >( buffer ), mWidth, mHeight, static_cast< size_t >( info.planes[0].stride ) );
255 mBuffers.push_back( SurfacePair( tbmSurface, surface ) );
259 mVectorRenderer->renderSync( frameNumber, surface );
261 tbm_surface_unmap( tbmSurface );
263 tbm_surface_queue_enqueue( mTbmQueue, tbmSurface );
265 if( !mResourceReady )
267 mPreviousTexture = mRenderedTexture; // It is used to destroy the object in the main thread.
268 mRenderedTexture = mTexture;
269 mResourceReady = true;
270 mResourceReadyTriggered = true;
272 TizenVectorAnimationManager::Get().TriggerEvent( *this );
274 DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::Render: Resource ready [current = %d] [%p]\n", frameNumber, this );
280 uint32_t TizenVectorAnimationRenderer::GetTotalFrameNumber() const
282 return mTotalFrameNumber;
285 float TizenVectorAnimationRenderer::GetFrameRate() const
290 void TizenVectorAnimationRenderer::GetDefaultSize( uint32_t& width, uint32_t& height ) const
292 width = mDefaultWidth;
293 height = mDefaultHeight;
296 void TizenVectorAnimationRenderer::GetLayerInfo( Property::Map& map ) const
298 Dali::Mutex::ScopedLock lock( mMutex );
300 if( mVectorRenderer )
302 auto layerInfo = mVectorRenderer->layers();
304 for( auto&& iter : layerInfo )
306 Property::Array frames;
307 frames.PushBack( std::get< 1 >( iter ) );
308 frames.PushBack( std::get< 2 >( iter ) );
309 map.Add( std::get< 0 >( iter ), frames );
314 bool TizenVectorAnimationRenderer::GetMarkerInfo( const std::string& marker, uint32_t& startFrame, uint32_t& endFrame ) const
316 Dali::Mutex::ScopedLock lock( mMutex );
318 if( mVectorRenderer )
320 auto markerList = mVectorRenderer->markers();
321 for( auto&& iter : markerList )
323 if( std::get< 0 >( iter ).compare( marker ) == 0 )
325 startFrame = static_cast< uint32_t >( std::get< 1 >( iter ) );
326 endFrame = static_cast< uint32_t >( std::get< 2 >( iter ) );
334 void TizenVectorAnimationRenderer::IgnoreRenderedFrame()
336 Dali::Mutex::ScopedLock lock( mMutex );
340 mTargetSurface->IgnoreSourceImage();
344 VectorAnimationRendererPlugin::UploadCompletedSignalType& TizenVectorAnimationRenderer::UploadCompletedSignal()
346 return mUploadCompletedSignal;
349 void TizenVectorAnimationRenderer::NotifyEvent()
351 Dali::Mutex::ScopedLock lock( mMutex );
353 if( mResourceReadyTriggered )
355 DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::NotifyEvent: Set Texture [%p]\n", this );
358 if( mRenderer && mRenderedTexture )
360 TextureSet textureSet = mRenderer.GetTextures();
361 textureSet.SetTexture( 0, mRenderedTexture );
364 mResourceReadyTriggered = false;
366 mUploadCompletedSignal.Emit();
369 mPreviousTexture.Reset();
372 void TizenVectorAnimationRenderer::SetShader()
379 Shader shader = mRenderer.GetShader();
381 std::string fragmentShader;
382 std::string vertexShader;
384 // Get custom fragment shader prefix
385 const char* fragmentPreFix = mTargetSurface->GetCustomFragmentPrefix();
388 fragmentShader = fragmentPreFix;
389 fragmentShader += "\n";
392 // Get the current fragment shader source
393 Property::Value program = shader.GetProperty( Shader::Property::PROGRAM );
394 Property::Map* map = program.GetMap();
397 Property::Value* fragment = map->Find( "fragment" );
400 fragmentShader += fragment->Get< std::string >();
403 Property::Value* vertex = map->Find( "vertex" );
406 vertexShader = vertex->Get< std::string >();
410 // Get custom sampler type name
411 const char* customSamplerTypename = mTargetSurface->GetCustomSamplerTypename();
412 if( customSamplerTypename )
414 size_t position = fragmentShader.find( DEFAULT_SAMPLER_TYPENAME );
415 if( position != std::string::npos )
417 fragmentShader.replace( position, strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename );
421 // Set the modified shader again
422 Shader newShader = Shader::New( vertexShader, fragmentShader );
423 newShader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
425 mRenderer.SetShader( newShader );
427 mShaderChanged = true;
430 void TizenVectorAnimationRenderer::ResetBuffers()
432 for( auto&& iter : mBuffers )
434 tbm_surface_internal_unref( iter.first );
439 } // namespace Plugin