CanvasRenderer: Use NativeImageSourceQueue in Tizen profile
[platform/core/uifw/dali-adaptor.git] / dali / internal / canvas-renderer / tizen / canvas-renderer-impl-tizen.cpp
1 /*
2  * Copyright (c) 2021 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/internal/canvas-renderer/tizen/canvas-renderer-impl-tizen.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/object/type-registry.h>
24
25 // INTERNAL INCLUDES
26 #include <dali/internal/canvas-renderer/common/drawable-group-impl.h>
27 #include <dali/internal/canvas-renderer/common/drawable-impl.h>
28 #include <dali/internal/canvas-renderer/common/gradient-impl.h>
29 #include <dali/internal/canvas-renderer/common/shape-impl.h>
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35 namespace Adaptor
36 {
37 namespace // unnamed namespace
38 {
39 // Type Registration
40 Dali::BaseHandle Create()
41 {
42   return Dali::BaseHandle();
43 }
44
45 Dali::TypeRegistration type(typeid(Dali::CanvasRenderer), typeid(Dali::BaseHandle), Create);
46
47 } // unnamed namespace
48
49 CanvasRendererTizen* CanvasRendererTizen::New(const Vector2& viewBox)
50 {
51   return new CanvasRendererTizen(viewBox);
52 }
53
54 CanvasRendererTizen::CanvasRendererTizen(const Vector2& viewBox)
55 :
56 #ifdef THORVG_SUPPORT
57   mRasterizedTexture(),
58   mMutex(),
59   mTvgCanvas(nullptr),
60   mTvgRoot(nullptr),
61   mNativeImageQueue(nullptr),
62 #endif
63   mSize(Vector2::ZERO),
64   mViewBox(Vector2::ZERO),
65   mChanged(false)
66 {
67   Initialize(viewBox);
68 }
69
70 CanvasRendererTizen::~CanvasRendererTizen()
71 {
72 #ifdef THORVG_SUPPORT
73   mDrawables.clear();
74
75   //Terminate ThorVG Engine
76   tvg::Initializer::term(tvg::CanvasEngine::Sw);
77 #endif
78 }
79
80 void CanvasRendererTizen::Initialize(const Vector2& viewBox)
81 {
82 #ifdef THORVG_SUPPORT
83   if(tvg::Initializer::init(tvg::CanvasEngine::Sw, 0 /*threads*/) != tvg::Result::Success)
84   {
85     DALI_LOG_ERROR("ThorVG engine initialize failed\n");
86   }
87   mTvgCanvas = tvg::SwCanvas::gen();
88
89   mSize = mViewBox = viewBox;
90   if(viewBox.width < 1.0f || viewBox.height < 1.0f)
91   {
92     return;
93   }
94
95   MakeTargetBuffer(mSize);
96 #endif
97 }
98
99 bool CanvasRendererTizen::Commit()
100 {
101 #ifdef THORVG_SUPPORT
102   Mutex::ScopedLock lock(mMutex);
103
104   if(mSize.width < 1.0f || mSize.height < 1.0f)
105   {
106     DALI_LOG_ERROR("Size is zero [%p]\n", this);
107     return false;
108   }
109
110   bool changed = false;
111
112   for(auto& it : mDrawables)
113   {
114     if(HaveDrawablesChanged(it))
115     {
116       UpdateDrawablesChanged(it, false);
117       changed = true;
118     }
119   }
120
121   if(!changed && !mChanged)
122   {
123     return false;
124   }
125   else
126   {
127     MakeTargetBuffer(mSize);
128     mChanged = false;
129   }
130
131   if(mTvgCanvas->clear() != tvg::Result::Success)
132   {
133     DALI_LOG_ERROR("ThorVG canvas clear fail [%p]\n", this);
134     return false;
135   }
136
137   auto scene = tvg::Scene::gen();
138   mTvgRoot   = scene.get();
139   for(auto& it : mDrawables)
140   {
141     PushDrawableToGroup(it, mTvgRoot);
142   }
143
144   if(mViewBox != mSize && mViewBox.width > 0 && mViewBox.height > 0)
145   {
146     auto scaleX = mSize.width / mViewBox.width;
147     auto scaleY = mSize.height / mViewBox.height;
148     mTvgRoot->scale(scaleX < scaleY ? scaleX : scaleY);
149   }
150
151   if(mTvgCanvas->push(move(scene)) != tvg::Result::Success)
152   {
153     DALI_LOG_ERROR("ThorVG canvas push fail [%p]\n", this);
154     return false;
155   }
156
157   return true;
158 #else
159   return false;
160 #endif
161 }
162
163 Dali::Texture CanvasRendererTizen::GetRasterizedTexture()
164 {
165 #ifdef THORVG_SUPPORT
166   if(mNativeImageQueue)
167   {
168     if(!mRasterizedTexture)
169     {
170       mRasterizedTexture = Dali::Texture::New(*mNativeImageQueue);
171     }
172     return mRasterizedTexture;
173   }
174   else
175   {
176     return Dali::Texture();
177   }
178 #else
179   return Dali::Texture();
180 #endif
181 }
182
183 bool CanvasRendererTizen::AddDrawable(Dali::CanvasRenderer::Drawable& drawable)
184 {
185 #ifdef THORVG_SUPPORT
186   Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
187   if(drawableImpl.IsAdded())
188   {
189     DALI_LOG_ERROR("Already added [%p][%p]\n", this, &drawable);
190     return false;
191   }
192
193   drawableImpl.SetAdded(true);
194   mDrawables.push_back(drawable);
195   mChanged = true;
196
197   return true;
198 #else
199   return false;
200 #endif
201 }
202
203 #ifdef THORVG_SUPPORT
204 bool CanvasRendererTizen::HaveDrawablesChanged(const Dali::CanvasRenderer::Drawable& drawable) const
205 {
206   const Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
207   if(drawableImpl.GetChanged())
208   {
209     return true;
210   }
211   Dali::CanvasRenderer::Drawable compositeDrawable = drawableImpl.GetCompositionDrawable();
212   if(DALI_UNLIKELY(compositeDrawable))
213   {
214     Internal::Adaptor::Drawable& compositeDrawableImpl = Dali::GetImplementation(compositeDrawable);
215     if(compositeDrawableImpl.GetChanged())
216     {
217       return true;
218     }
219   }
220
221   if(drawableImpl.GetType() == Drawable::Types::DRAWABLE_GROUP)
222   {
223     const Dali::CanvasRenderer::DrawableGroup& group             = static_cast<const Dali::CanvasRenderer::DrawableGroup&>(drawable);
224     const Internal::Adaptor::DrawableGroup&    drawableGroupImpl = Dali::GetImplementation(group);
225     DrawableGroup::DrawableVector              drawables         = drawableGroupImpl.GetDrawables();
226     for(auto& it : drawables)
227     {
228       if(HaveDrawablesChanged(it))
229       {
230         return true;
231       }
232     }
233   }
234   else if(drawableImpl.GetType() == Drawable::Types::SHAPE)
235   {
236     const Dali::CanvasRenderer::Shape& shape        = static_cast<const Dali::CanvasRenderer::Shape&>(drawable);
237     Dali::CanvasRenderer::Gradient     fillGradient = shape.GetFillGradient();
238     if(DALI_UNLIKELY(fillGradient))
239     {
240       Internal::Adaptor::Gradient& fillGradientImpl = Dali::GetImplementation(fillGradient);
241       if(fillGradientImpl.GetChanged())
242       {
243         return true;
244       }
245     }
246
247     Dali::CanvasRenderer::Gradient strokeGradient = shape.GetStrokeGradient();
248     if(DALI_UNLIKELY(strokeGradient))
249     {
250       Internal::Adaptor::Gradient& strokeGradientImpl = Dali::GetImplementation(strokeGradient);
251       if(strokeGradientImpl.GetChanged())
252       {
253         return true;
254       }
255     }
256   }
257
258   return false;
259 }
260
261 void CanvasRendererTizen::UpdateDrawablesChanged(Dali::CanvasRenderer::Drawable& drawable, bool changed)
262 {
263   Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
264   drawableImpl.SetChanged(changed);
265
266   Dali::CanvasRenderer::Drawable compositeDrawable = drawableImpl.GetCompositionDrawable();
267   if(DALI_UNLIKELY(compositeDrawable))
268   {
269     Internal::Adaptor::Drawable& compositeDrawableImpl = Dali::GetImplementation(compositeDrawable);
270     compositeDrawableImpl.SetChanged(changed);
271   }
272
273   if(drawableImpl.GetType() == Drawable::Types::DRAWABLE_GROUP)
274   {
275     Dali::CanvasRenderer::DrawableGroup& group             = static_cast<Dali::CanvasRenderer::DrawableGroup&>(drawable);
276     Internal::Adaptor::DrawableGroup&    drawableGroupImpl = Dali::GetImplementation(group);
277     DrawableGroup::DrawableVector        drawables         = drawableGroupImpl.GetDrawables();
278     for(auto& it : drawables)
279     {
280       UpdateDrawablesChanged(it, changed);
281     }
282   }
283   else if(drawableImpl.GetType() == Drawable::Types::SHAPE)
284   {
285     Dali::CanvasRenderer::Shape&   shape        = static_cast<Dali::CanvasRenderer::Shape&>(drawable);
286     Dali::CanvasRenderer::Gradient fillGradient = shape.GetFillGradient();
287     if(DALI_UNLIKELY(fillGradient))
288     {
289       Internal::Adaptor::Gradient& fillGradientImpl = Dali::GetImplementation(fillGradient);
290       fillGradientImpl.SetChanged(changed);
291     }
292
293     Dali::CanvasRenderer::Gradient strokeGradient = shape.GetStrokeGradient();
294     if(DALI_UNLIKELY(strokeGradient))
295     {
296       Internal::Adaptor::Gradient& strokeGradientImpl = Dali::GetImplementation(strokeGradient);
297       strokeGradientImpl.SetChanged(changed);
298     }
299   }
300 }
301 #endif
302
303 bool CanvasRendererTizen::IsCanvasChanged() const
304 {
305 #ifdef THORVG_SUPPORT
306   if(mChanged)
307   {
308     return true;
309   }
310
311   for(auto& it : mDrawables)
312   {
313     if(HaveDrawablesChanged(it))
314     {
315       return true;
316     }
317   }
318 #endif
319   return false;
320 }
321
322 bool CanvasRendererTizen::Rasterize()
323 {
324 #ifdef THORVG_SUPPORT
325   Mutex::ScopedLock lock(mMutex);
326
327   if(mNativeImageQueue && mNativeImageQueue->CanDequeueBuffer())
328   {
329     uint32_t width, height, stride;
330     uint8_t* buffer = mNativeImageQueue->DequeueBuffer(width, height, stride);
331     if(!buffer)
332     {
333       DALI_LOG_ERROR("Pixel buffer create to fail [%p]\n", this);
334       return false;
335     }
336
337     mTvgCanvas->target(reinterpret_cast<uint32_t*>(buffer), width, width, height, tvg::SwCanvas::ARGB8888);
338
339     if(mTvgCanvas->draw() != tvg::Result::Success)
340     {
341       DALI_LOG_ERROR("ThorVG Draw fail [%p]\n", this);
342       mNativeImageQueue->EnqueueBuffer(buffer);
343       return false;
344     }
345
346     mTvgCanvas->sync();
347
348     mNativeImageQueue->EnqueueBuffer(buffer);
349   }
350   else
351   {
352     return false;
353   }
354
355   return true;
356 #else
357   return false;
358 #endif
359 }
360
361 bool CanvasRendererTizen::RemoveDrawable(Dali::CanvasRenderer::Drawable& drawable)
362 {
363 #ifdef THORVG_SUPPORT
364   DrawableGroup::DrawableVector::iterator it = std::find(mDrawables.begin(), mDrawables.end(), drawable);
365   if(it != mDrawables.end())
366   {
367     Internal::Adaptor::Drawable& drawableImpl = GetImplementation(drawable);
368     drawableImpl.SetAdded(false);
369
370     mDrawables.erase(it);
371     mChanged = true;
372
373     return true;
374   }
375
376 #endif
377   return false;
378 }
379
380 bool CanvasRendererTizen::RemoveAllDrawables()
381 {
382 #ifdef THORVG_SUPPORT
383   for(auto& it : mDrawables)
384   {
385     Internal::Adaptor::Drawable& drawableImpl = GetImplementation(it);
386     drawableImpl.SetAdded(false);
387   }
388
389   mDrawables.clear();
390   mChanged = true;
391
392   return true;
393 #else
394   return false;
395 #endif
396 }
397
398 bool CanvasRendererTizen::SetSize(Vector2 size)
399 {
400   if(size.width < 1.0f || size.height < 1.0f)
401   {
402     return false;
403   }
404
405   if(size != mSize)
406   {
407     mSize    = size;
408     mChanged = true;
409   }
410
411   return true;
412 }
413
414 Vector2 CanvasRendererTizen::GetSize() const
415 {
416   return mSize;
417 }
418
419 bool CanvasRendererTizen::SetViewBox(const Vector2& viewBox)
420 {
421   if(viewBox.width < 1.0f || viewBox.height < 1.0f)
422   {
423     return false;
424   }
425
426   if(viewBox != mViewBox)
427   {
428     mViewBox = viewBox;
429     mChanged = true;
430   }
431
432   return true;
433 }
434
435 const Vector2& CanvasRendererTizen::GetViewBox()
436 {
437   return mViewBox;
438 }
439
440 void CanvasRendererTizen::MakeTargetBuffer(const Vector2& size)
441 {
442 #ifdef THORVG_SUPPORT
443   if(!mNativeImageQueue)
444   {
445     mNativeImageQueue = Dali::NativeImageSourceQueue::New(size.width, size.height, Dali::NativeImageSourceQueue::ColorFormat::RGBA8888);
446   }
447   else if(size.width != mSize.width || size.height != mSize.height)
448   {
449     mNativeImageQueue->SetSize(static_cast<uint32_t>(size.width), static_cast<uint32_t>(size.height));
450   }
451 #endif
452 }
453
454 #ifdef THORVG_SUPPORT
455 void CanvasRendererTizen::PushDrawableToGroup(Dali::CanvasRenderer::Drawable& drawable, tvg::Scene* parent)
456 {
457   Internal::Adaptor::Drawable& drawableImpl        = Dali::GetImplementation(drawable);
458   tvg::Paint*                  tvgDuplicatedObject = static_cast<tvg::Paint*>(drawableImpl.GetObject())->duplicate();
459   if(!tvgDuplicatedObject)
460   {
461     DALI_LOG_ERROR("Invalid drawable object [%p]\n", this);
462     return;
463   }
464   Drawable::Types type = drawableImpl.GetType();
465
466   if(type == Drawable::Types::DRAWABLE_GROUP)
467   {
468     Dali::CanvasRenderer::DrawableGroup& group             = static_cast<Dali::CanvasRenderer::DrawableGroup&>(drawable);
469     Internal::Adaptor::DrawableGroup&    drawableGroupImpl = Dali::GetImplementation(group);
470     DrawableGroup::DrawableVector        drawables         = drawableGroupImpl.GetDrawables();
471     for(auto& it : drawables)
472     {
473       PushDrawableToGroup(it, static_cast<tvg::Scene*>(tvgDuplicatedObject));
474     }
475   }
476   else if(type == Drawable::Types::SHAPE)
477   {
478     //FillGradient
479     Dali::CanvasRenderer::Shape&   shape        = static_cast<Dali::CanvasRenderer::Shape&>(drawable);
480     Dali::CanvasRenderer::Gradient fillGradient = shape.GetFillGradient();
481     if(DALI_UNLIKELY(fillGradient))
482     {
483       Internal::Adaptor::Gradient& fillGradientImpl          = Dali::GetImplementation(fillGradient);
484       tvg::Fill*                   tvgDuplicatedFillGradient = static_cast<tvg::Fill*>(fillGradientImpl.GetObject())->duplicate();
485       if(!tvgDuplicatedFillGradient)
486       {
487         DALI_LOG_ERROR("Invalid gradient object [%p]\n", this);
488         return;
489       }
490       if(static_cast<tvg::Shape*>(tvgDuplicatedObject)->fill(std::unique_ptr<tvg::Fill>(tvgDuplicatedFillGradient)) != tvg::Result::Success)
491       {
492         DALI_LOG_ERROR("Tvg gradient set fail [%p]\n", this);
493         return;
494       }
495     }
496
497     //StrokeGradient
498     Dali::CanvasRenderer::Gradient strokeGradient = shape.GetStrokeGradient();
499     if(DALI_UNLIKELY(strokeGradient))
500     {
501       Internal::Adaptor::Gradient& strokeGradientImpl          = Dali::GetImplementation(strokeGradient);
502       tvg::Fill*                   tvgDuplicatedStrokeGradient = static_cast<tvg::Fill*>(strokeGradientImpl.GetObject())->duplicate();
503       if(!tvgDuplicatedStrokeGradient)
504       {
505         DALI_LOG_ERROR("Invalid gradient object [%p]\n", this);
506         return;
507       }
508       if(static_cast<tvg::Shape*>(tvgDuplicatedObject)->stroke(std::unique_ptr<tvg::Fill>(tvgDuplicatedStrokeGradient)) != tvg::Result::Success)
509       {
510         DALI_LOG_ERROR("Tvg gradient set fail [%p]\n", this);
511         return;
512       }
513     }
514   }
515
516   Dali::CanvasRenderer::Drawable compositeDrawable = drawableImpl.GetCompositionDrawable();
517   if(DALI_UNLIKELY(compositeDrawable))
518   {
519     Internal::Adaptor::Drawable& compositeDrawableImpl = Dali::GetImplementation(compositeDrawable);
520     tvg::Paint*                  tvgCompositeObject    = static_cast<tvg::Paint*>(compositeDrawableImpl.GetObject());
521     if(tvgCompositeObject)
522     {
523       tvg::Paint*     tvgDuplicatedCompositeObject = tvgCompositeObject->duplicate();
524       Drawable::Types type                         = compositeDrawableImpl.GetType();
525
526       if(type == Drawable::Types::DRAWABLE_GROUP)
527       {
528         Dali::CanvasRenderer::DrawableGroup& compositeGroup             = static_cast<Dali::CanvasRenderer::DrawableGroup&>(compositeDrawable);
529         Internal::Adaptor::DrawableGroup&    compositeDrawableGroupImpl = Dali::GetImplementation(compositeGroup);
530         DrawableGroup::DrawableVector        compositeDrawables         = compositeDrawableGroupImpl.GetDrawables();
531         for(auto& it : compositeDrawables)
532         {
533           PushDrawableToGroup(it, static_cast<tvg::Scene*>(tvgDuplicatedCompositeObject));
534         }
535       }
536
537       if(tvgDuplicatedObject->composite(std::move(std::unique_ptr<tvg::Paint>(tvgDuplicatedCompositeObject)), static_cast<tvg::CompositeMethod>(drawableImpl.GetCompositionType())) != tvg::Result::Success)
538       {
539         DALI_LOG_ERROR("Tvg composite fail [%p]\n", this);
540         return;
541       }
542     }
543   }
544
545   if(parent->push(std::move(std::unique_ptr<tvg::Paint>(tvgDuplicatedObject))) != tvg::Result::Success)
546   {
547     DALI_LOG_ERROR("Tvg push fail [%p]\n", this);
548     return;
549   }
550 }
551 #endif
552
553 } // namespace Adaptor
554
555 } // namespace Internal
556
557 } // namespace Dali