(Vector) Ignore previous image when the queue is full
[platform/core/uifw/dali-extension.git] / dali-extension / vector-animation-renderer / tizen-vector-animation-renderer.cpp
1 /*
2  * Copyright (c) 2019 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/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>
27
28 // INTERNAL INCLUDES
29 #include <dali-extension/vector-animation-renderer/tizen-vector-animation-manager.h>
30
31 // The plugin factories
32 extern "C" DALI_EXPORT_API Dali::VectorAnimationRendererPlugin* CreateVectorAnimationRendererPlugin( void )
33 {
34   return new Dali::Plugin::TizenVectorAnimationRenderer;
35 }
36
37 namespace Dali
38 {
39
40 namespace Plugin
41 {
42
43 namespace
44 {
45
46 const char* const DEFAULT_SAMPLER_TYPENAME( "sampler2D" );
47 const char* const PIXEL_AREA_UNIFORM_NAME( "pixelArea" );
48
49 const Vector4 FULL_TEXTURE_RECT( 0.f, 0.f, 1.f, 1.f );
50
51 } // unnamed namespace
52
53 TizenVectorAnimationRenderer::TizenVectorAnimationRenderer()
54 : mUrl(),
55   mBuffers(),
56   mMutex(),
57   mRenderer(),
58   mTexture(),
59   mRenderedTexture(),
60   mPreviousTexture(),
61   mTargetSurface(),
62   mVectorRenderer(),
63   mUploadCompletedSignal(),
64   mTbmQueue( NULL ),
65   mTotalFrameNumber( 0 ),
66   mWidth( 0 ),
67   mHeight( 0 ),
68   mDefaultWidth( 0 ),
69   mDefaultHeight( 0 ),
70   mFrameRate( 60.0f ),
71   mResourceReady( false ),
72   mShaderChanged( false ),
73   mResourceReadyTriggered( false )
74 {
75 }
76
77 TizenVectorAnimationRenderer::~TizenVectorAnimationRenderer()
78 {
79   Dali::Mutex::ScopedLock lock( mMutex );
80
81   ResetBuffers();
82   DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::~TizenVectorAnimationRenderer: this = %p\n", this );
83 }
84
85 bool TizenVectorAnimationRenderer::Initialize( const std::string& url )
86 {
87   mUrl = url;
88
89   mVectorRenderer = rlottie::Animation::loadFromFile( mUrl );
90   if( !mVectorRenderer )
91   {
92     DALI_LOG_ERROR( "Failed to load a Lottie file [%s] [%p]\n", mUrl.c_str(), this );
93     return false;
94   }
95
96   mTotalFrameNumber = mVectorRenderer->totalFrame();
97   mFrameRate = static_cast< float >( mVectorRenderer->frameRate() );
98
99   size_t w, h;
100   mVectorRenderer->size( w, h );
101   mDefaultWidth = static_cast< uint32_t >( w );
102   mDefaultHeight = static_cast< uint32_t >( h );
103
104   TizenVectorAnimationManager::Get().AddEventHandler( *this );
105
106   DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::Initialize: file [%s] [%p]\n", url.c_str(), this );
107
108   return true;
109 }
110
111 void TizenVectorAnimationRenderer::Finalize()
112 {
113   Dali::Mutex::ScopedLock lock( mMutex );
114
115   TizenVectorAnimationManager::Get().RemoveEventHandler( *this );
116
117   mRenderer.Reset();
118   mTexture.Reset();
119   mRenderedTexture.Reset();
120   mPreviousTexture.Reset();
121   mVectorRenderer.reset();
122
123   mTargetSurface = nullptr;
124   mTbmQueue = NULL;
125
126   DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::Finalize: [%p]\n", this );
127 }
128
129 void TizenVectorAnimationRenderer::SetRenderer( Renderer renderer )
130 {
131   mRenderer = renderer;
132   mShaderChanged = false;
133
134   if( mTargetSurface )
135   {
136     Dali::Mutex::ScopedLock lock( mMutex );
137
138     if( mResourceReady && mRenderedTexture )
139     {
140       TextureSet textureSet = renderer.GetTextures();
141
142       textureSet.SetTexture( 0, mRenderedTexture );
143
144       mUploadCompletedSignal.Emit();
145     }
146
147     SetShader();
148   }
149 }
150
151 void TizenVectorAnimationRenderer::SetSize( uint32_t width, uint32_t height )
152 {
153   Dali::Mutex::ScopedLock lock( mMutex );
154
155   if( mWidth == width && mHeight == height )
156   {
157     DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::SetSize: Same size (%d, %d) [%p]\n", mWidth, mHeight, this );
158     return;
159   }
160
161   mTargetSurface = NativeImageSourceQueue::New( width, height, NativeImageSourceQueue::COLOR_DEPTH_DEFAULT );
162
163   mTexture = Texture::New( *mTargetSurface );
164
165   if( mRenderer )
166   {
167     SetShader();
168   }
169
170   mTbmQueue = AnyCast< tbm_surface_queue_h >( mTargetSurface->GetNativeImageSourceQueue() );
171
172   mWidth = width;
173   mHeight = height;
174
175   mResourceReady = false;
176
177   // Reset the previous texture to destroy it in the main thread
178   mPreviousTexture.Reset();
179
180   DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::SetSize: width = %d, height = %d [%p]\n", mWidth, mHeight, this );
181 }
182
183 bool TizenVectorAnimationRenderer::Render( uint32_t frameNumber )
184 {
185   Dali::Mutex::ScopedLock lock( mMutex );
186
187   if( !mTbmQueue || !mVectorRenderer || !mTargetSurface )
188   {
189     return false;
190   }
191
192   int canDequeue = tbm_surface_queue_can_dequeue( mTbmQueue, 0 );
193   if( !canDequeue )
194   {
195     // Ignore the previous image which is inserted to the queue.
196     mTargetSurface->IgnoreSourceImage();
197
198     // Check again
199     canDequeue = tbm_surface_queue_can_dequeue( mTbmQueue, 0 );
200     if( !canDequeue )
201     {
202       return false;
203     }
204   }
205
206   tbm_surface_h tbmSurface;
207
208   if( tbm_surface_queue_dequeue( mTbmQueue, &tbmSurface ) != TBM_SURFACE_QUEUE_ERROR_NONE )
209   {
210     DALI_LOG_ERROR( "Failed to dequeue a tbm_surface [%p]\n", this );
211     return false;
212   }
213
214   tbm_surface_info_s info;
215   tbm_surface_map( tbmSurface, TBM_OPTION_WRITE, &info );
216
217   rlottie::Surface surface;
218   bool existing = false;
219
220   if( !mResourceReady )
221   {
222     // Need to reset buffer list
223     ResetBuffers();
224   }
225   else
226   {
227     for( auto&& iter : mBuffers )
228     {
229       if( iter.first == tbmSurface )
230       {
231         // Find the buffer in the existing list
232         existing = true;
233         surface = iter.second;
234         break;
235       }
236     }
237   }
238
239   if( !existing )
240   {
241     unsigned char* buffer = info.planes[0].ptr;
242     if( !buffer )
243     {
244       DALI_LOG_ERROR( "TizenVectorAnimationRenderer::Render: tbm buffer pointer is null! [%p]\n", this );
245       tbm_surface_unmap( tbmSurface );
246       return false;
247     }
248
249     tbm_surface_internal_ref( tbmSurface );
250
251     // Create Surface object
252     surface = rlottie::Surface( reinterpret_cast< uint32_t* >( buffer ), mWidth, mHeight, static_cast< size_t >( info.planes[0].stride ) );
253
254     // Push the buffer
255     mBuffers.push_back( SurfacePair( tbmSurface, surface ) );
256   }
257
258   // Render the frame
259   mVectorRenderer->renderSync( frameNumber, surface );
260
261   tbm_surface_unmap( tbmSurface );
262
263   tbm_surface_queue_enqueue( mTbmQueue, tbmSurface );
264
265   if( !mResourceReady )
266   {
267     mPreviousTexture = mRenderedTexture;  // It is used to destroy the object in the main thread.
268     mRenderedTexture = mTexture;
269     mResourceReady = true;
270     mResourceReadyTriggered = true;
271
272     TizenVectorAnimationManager::Get().TriggerEvent( *this );
273
274     DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::Render: Resource ready [current = %d] [%p]\n", frameNumber, this );
275   }
276
277   return true;
278 }
279
280 uint32_t TizenVectorAnimationRenderer::GetTotalFrameNumber() const
281 {
282   return mTotalFrameNumber;
283 }
284
285 float TizenVectorAnimationRenderer::GetFrameRate() const
286 {
287   return mFrameRate;
288 }
289
290 void TizenVectorAnimationRenderer::GetDefaultSize( uint32_t& width, uint32_t& height ) const
291 {
292   width = mDefaultWidth;
293   height = mDefaultHeight;
294 }
295
296 void TizenVectorAnimationRenderer::GetLayerInfo( Property::Map& map ) const
297 {
298   Dali::Mutex::ScopedLock lock( mMutex );
299
300   if( mVectorRenderer )
301   {
302     auto layerInfo = mVectorRenderer->layers();
303
304     for( auto&& iter : layerInfo )
305     {
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 );
310     }
311   }
312 }
313
314 bool TizenVectorAnimationRenderer::GetMarkerInfo( const std::string& marker, uint32_t& startFrame, uint32_t& endFrame ) const
315 {
316   Dali::Mutex::ScopedLock lock( mMutex );
317
318   if( mVectorRenderer )
319   {
320     auto markerList = mVectorRenderer->markers();
321     for( auto&& iter : markerList )
322     {
323       if( std::get< 0 >( iter ).compare( marker ) == 0 )
324       {
325         startFrame = static_cast< uint32_t >( std::get< 1 >( iter ) );
326         endFrame = static_cast< uint32_t >( std::get< 2 >( iter ) );
327         return true;
328       }
329     }
330   }
331   return false;
332 }
333
334 void TizenVectorAnimationRenderer::IgnoreRenderedFrame()
335 {
336   Dali::Mutex::ScopedLock lock( mMutex );
337
338   if( mTargetSurface )
339   {
340     mTargetSurface->IgnoreSourceImage();
341   }
342 }
343
344 VectorAnimationRendererPlugin::UploadCompletedSignalType& TizenVectorAnimationRenderer::UploadCompletedSignal()
345 {
346   return mUploadCompletedSignal;
347 }
348
349 void TizenVectorAnimationRenderer::NotifyEvent()
350 {
351   Dali::Mutex::ScopedLock lock( mMutex );
352
353   if( mResourceReadyTriggered )
354   {
355     DALI_LOG_RELEASE_INFO( "TizenVectorAnimationRenderer::NotifyEvent: Set Texture [%p]\n", this );
356
357     // Set texture
358     if( mRenderer && mRenderedTexture )
359     {
360       TextureSet textureSet = mRenderer.GetTextures();
361       textureSet.SetTexture( 0, mRenderedTexture );
362     }
363
364     mResourceReadyTriggered = false;
365
366     mUploadCompletedSignal.Emit();
367   }
368
369   mPreviousTexture.Reset();
370 }
371
372 void TizenVectorAnimationRenderer::SetShader()
373 {
374   if( mShaderChanged )
375   {
376     return;
377   }
378
379   Shader shader = mRenderer.GetShader();
380
381   std::string fragmentShader;
382   std::string vertexShader;
383
384   // Get custom fragment shader prefix
385   const char* fragmentPreFix = mTargetSurface->GetCustomFragmentPrefix();
386   if( fragmentPreFix )
387   {
388     fragmentShader = fragmentPreFix;
389     fragmentShader += "\n";
390   }
391
392   // Get the current fragment shader source
393   Property::Value program = shader.GetProperty( Shader::Property::PROGRAM );
394   Property::Map* map = program.GetMap();
395   if( map )
396   {
397     Property::Value* fragment = map->Find( "fragment" );
398     if( fragment )
399     {
400       fragmentShader += fragment->Get< std::string >();
401     }
402
403     Property::Value* vertex = map->Find( "vertex" );
404     if( vertex )
405     {
406       vertexShader = vertex->Get< std::string >();
407     }
408   }
409
410   // Get custom sampler type name
411   const char* customSamplerTypename = mTargetSurface->GetCustomSamplerTypename();
412   if( customSamplerTypename )
413   {
414     size_t position = fragmentShader.find( DEFAULT_SAMPLER_TYPENAME );
415     if( position != std::string::npos )
416     {
417       fragmentShader.replace( position, strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename );
418     }
419   }
420
421   // Set the modified shader again
422   Shader newShader = Shader::New( vertexShader, fragmentShader );
423   newShader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
424
425   mRenderer.SetShader( newShader );
426
427   mShaderChanged = true;
428 }
429
430 void TizenVectorAnimationRenderer::ResetBuffers()
431 {
432   for( auto&& iter : mBuffers )
433   {
434     tbm_surface_internal_unref( iter.first );
435   }
436   mBuffers.clear();
437 }
438
439 } // namespace Plugin
440
441 } // namespace Dali;