[Tizen] Clear previous textures when event triggered
[platform/core/uifw/dali-extension.git] / dali-extension / vector-animation-renderer / vector-animation-renderer-tizen.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/vector-animation-renderer-tizen.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/vector-animation-plugin-manager.h>
31
32 // The plugin factories
33 extern "C" DALI_EXPORT_API Dali::VectorAnimationRendererPlugin* CreateVectorAnimationRendererPlugin(void)
34 {
35   return new Dali::Plugin::VectorAnimationRendererTizen;
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 VectorAnimationRendererTizen::VectorAnimationRendererTizen()
53 : mBuffers(),
54   mRenderedTexture(),
55   mPreviousTextures(),
56   mTargetSurface(),
57   mTbmQueue(NULL)
58 {
59 }
60
61 VectorAnimationRendererTizen::~VectorAnimationRendererTizen()
62 {
63   Dali::Mutex::ScopedLock lock(mMutex);
64
65   ResetBuffers();
66   DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "this = %p\n", this);
67 }
68
69 bool VectorAnimationRendererTizen::Render(uint32_t frameNumber)
70 {
71   Dali::Mutex::ScopedLock lock(mMutex);
72
73   if(mEnableFixedCache)
74   {
75     if(mDecodedBuffers.size() < mTotalFrameNumber)
76     {
77       mDecodedBuffers.clear();
78       mDecodedBuffers.resize(mTotalFrameNumber, std::make_pair<std::vector<uint8_t>, bool>(std::vector<uint8_t>(), false));
79     }
80   }
81
82   if(!mTbmQueue || !mVectorRenderer || !mTargetSurface)
83   {
84     return false;
85   }
86
87   int canDequeue = tbm_surface_queue_can_dequeue(mTbmQueue, 0);
88   if(!canDequeue)
89   {
90     // Ignore the previous image which is inserted to the queue.
91     mTargetSurface->IgnoreSourceImage();
92
93     // Check again
94     canDequeue = tbm_surface_queue_can_dequeue(mTbmQueue, 0);
95     if(!canDequeue)
96     {
97       return false;
98     }
99   }
100
101   tbm_surface_h tbmSurface;
102
103   if(tbm_surface_queue_dequeue(mTbmQueue, &tbmSurface) != TBM_SURFACE_QUEUE_ERROR_NONE)
104   {
105     DALI_LOG_ERROR("Failed to dequeue a tbm_surface [%p]\n", this);
106     return false;
107   }
108
109   tbm_surface_info_s info;
110   int                ret = TBM_SURFACE_ERROR_NONE;
111
112   if(mEnableFixedCache && (frameNumber < mDecodedBuffers.size()) && (!mDecodedBuffers[frameNumber].second))
113   {
114     ret = tbm_surface_map(tbmSurface, TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, &info);
115   }
116   else
117   {
118     ret = tbm_surface_map(tbmSurface, TBM_SURF_OPTION_WRITE, &info);
119   }
120   if(ret != TBM_SURFACE_ERROR_NONE)
121   {
122     DALI_LOG_ERROR("VectorAnimationRendererTizen::Render: tbm_surface_map is failed! [%d] [%p]\n", ret, this);
123     tbm_surface_queue_cancel_dequeue(mTbmQueue, tbmSurface);
124     return false;
125   }
126
127   unsigned char* buffer = info.planes[0].ptr;
128   if(info.width != mWidth || info.height != mHeight || !buffer)
129   {
130     DALI_LOG_ERROR("VectorAnimationRendererTizen::Render: Invalid tbm surface! [%d, %d, %p] [%p]\n", info.width, info.height, buffer, this);
131     tbm_surface_unmap(tbmSurface);
132     tbm_surface_queue_cancel_dequeue(mTbmQueue, tbmSurface);
133     return false;
134   }
135
136   rlottie::Surface surface;
137   bool             existing = false;
138
139   if(!mResourceReady)
140   {
141     // Need to reset buffer list
142     ResetBuffers();
143   }
144   else
145   {
146     for(auto&& iter : mBuffers)
147     {
148       if(iter.first == tbmSurface)
149       {
150         // Find the buffer in the existing list
151         existing = true;
152         surface  = iter.second;
153         break;
154       }
155     }
156   }
157
158   if(mEnableFixedCache && (frameNumber < mDecodedBuffers.size()) && mDecodedBuffers[frameNumber].second)
159   {
160     const int bufferSize = mWidth * mHeight * Dali::Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
161     memcpy(buffer, &mDecodedBuffers[frameNumber].first[0], bufferSize);
162   }
163   else
164   {
165     if(!existing)
166     {
167       tbm_surface_internal_ref(tbmSurface);
168
169       // Create Surface object
170       surface = rlottie::Surface(reinterpret_cast<uint32_t*>(buffer), mWidth, mHeight, static_cast<size_t>(info.planes[0].stride));
171
172       // Push the buffer
173       mBuffers.push_back(SurfacePair(tbmSurface, surface));
174     }
175
176     if(mEnableFixedCache && (frameNumber < mDecodedBuffers.size()))
177     {
178       const uint32_t       bufferSize = mWidth * mHeight * Dali::Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
179       std::vector<uint8_t> rasterizeBuffer(buffer, buffer + bufferSize);
180       mDecodedBuffers[frameNumber].first  = std::move(rasterizeBuffer);
181       mDecodedBuffers[frameNumber].second = true;
182     }
183   }
184
185   // Render the frame
186   mVectorRenderer->renderSync(frameNumber, surface);
187
188   tbm_surface_unmap(tbmSurface);
189
190   tbm_surface_queue_enqueue(mTbmQueue, tbmSurface);
191
192   if(!mResourceReady)
193   {
194     mPreviousTextures.push_back(mRenderedTexture); // It is used to destroy the object in the main thread.
195
196     mRenderedTexture        = mTexture;
197     mResourceReady          = true;
198     mResourceReadyTriggered = true;
199
200     VectorAnimationPluginManager::Get().TriggerEvent(*this);
201
202     DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Resource ready [current = %d] [%p]\n", frameNumber, this);
203   }
204
205   return true;
206 }
207
208 void VectorAnimationRendererTizen::RenderStopped()
209 {
210   if(mTargetSurface)
211   {
212     // Animation is stopped. Free empty buffers
213     mTargetSurface->FreeReleasedBuffers();
214
215     {
216       Dali::Mutex::ScopedLock lock(mMutex);
217       ResetBuffers();
218     }
219   }
220 }
221
222 void VectorAnimationRendererTizen::SetShader()
223 {
224   if(mShaderChanged)
225   {
226     return;
227   }
228
229   Shader shader = mRenderer.GetShader();
230
231   std::string fragmentShader;
232   std::string vertexShader;
233
234   // Get the current fragment shader source
235   Property::Value program = shader.GetProperty(Shader::Property::PROGRAM);
236   Property::Map*  map     = program.GetMap();
237   if(map)
238   {
239     Property::Value* fragment = map->Find("fragment");
240     if(fragment)
241     {
242       fragmentShader = fragment->Get<std::string>();
243     }
244
245     Property::Value* vertex = map->Find("vertex");
246     if(vertex)
247     {
248       vertexShader = vertex->Get<std::string>();
249     }
250   }
251
252   // Get custom fragment shader prefix
253   mTargetSurface->ApplyNativeFragmentShader(fragmentShader);
254
255   // Set the modified shader again
256   Shader newShader = Shader::New(vertexShader, fragmentShader);
257   newShader.RegisterProperty(PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT);
258
259   mRenderer.SetShader(newShader);
260
261   mShaderChanged = true;
262 }
263
264 void VectorAnimationRendererTizen::ResetBuffers()
265 {
266   for(auto&& iter : mBuffers)
267   {
268     tbm_surface_internal_unref(iter.first);
269   }
270   mBuffers.clear();
271 }
272
273 void VectorAnimationRendererTizen::OnFinalize()
274 {
275   mRenderedTexture.Reset();
276   mPreviousTextures.clear();
277
278   mTargetSurface = nullptr;
279   mTbmQueue      = NULL;
280 }
281
282 void VectorAnimationRendererTizen::OnSetSize()
283 {
284   mTbmQueue = AnyCast<tbm_surface_queue_h>(mTargetSurface->GetNativeImageSourceQueue());
285
286   // Reset the previous texture to destroy it in the main thread
287   mPreviousTextures.clear();
288 }
289
290 void VectorAnimationRendererTizen::OnNotify()
291 {
292   // Reset the previous texture to destroy it in the main thread
293   mPreviousTextures.clear();
294 }
295
296 void VectorAnimationRendererTizen::PrepareTarget()
297 {
298   mTargetSurface = NativeImageSourceQueue::New(mWidth, mHeight, NativeImageSourceQueue::ColorFormat::RGBA8888);
299
300   mTexture = Texture::New(*mTargetSurface);
301 }
302
303 bool VectorAnimationRendererTizen::IsTargetPrepared()
304 {
305   return !!mTargetSurface;
306 }
307
308 bool VectorAnimationRendererTizen::IsRenderReady()
309 {
310   return (mResourceReady && mRenderedTexture);
311 }
312
313 Dali::Texture VectorAnimationRendererTizen::GetTargetTexture()
314 {
315   return mRenderedTexture;
316 }
317
318 } // namespace Plugin
319
320 } // namespace Dali