Merge "Add CanvasView thread rasterization" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / canvas-view / canvas-view-impl.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 "canvas-view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/scripting/scripting.h>
23 #include <dali/integration-api/adaptor-framework/adaptor.h>
24 #include <dali/public-api/object/type-registry-helper.h>
25 #include <dali/public-api/object/type-registry.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/devel-api/controls/control-devel.h>
29 #include <dali-toolkit/internal/controls/canvas-view/canvas-view-rasterize-thread.h>
30 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
31 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
32 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
33
34 namespace Dali
35 {
36 namespace Toolkit
37 {
38 namespace Internal
39 {
40 namespace
41 {
42 BaseHandle Create()
43 {
44   return BaseHandle();
45 }
46 // Setup properties, signals and actions using the type-registry.
47 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::CanvasView, Toolkit::Control, Create);
48 DALI_TYPE_REGISTRATION_END()
49 } // anonymous namespace
50
51 using namespace Dali;
52
53 CanvasView::CanvasView(const Vector2& viewBox)
54 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
55   mCanvasRenderer(CanvasRenderer::New(viewBox)),
56   mTexture(),
57   mTextureSet(),
58   mSize(viewBox),
59   mCanvasViewRasterizeThread(nullptr)
60 {
61 }
62
63 CanvasView::~CanvasView()
64 {
65   if(mCanvasViewRasterizeThread)
66   {
67     mCanvasViewRasterizeThread->RemoveTask(this);
68
69     CanvasViewRasterizeThread::TerminateThread(mCanvasViewRasterizeThread);
70   }
71
72   if(Adaptor::IsAvailable())
73   {
74     Adaptor::Get().UnregisterProcessor(*this);
75   }
76 }
77
78 Toolkit::CanvasView CanvasView::New(const Vector2& viewBox)
79 {
80   CanvasView* impl = new CanvasView(viewBox);
81
82   Toolkit::CanvasView handle = Toolkit::CanvasView(*impl);
83
84   // Second-phase init of the implementation
85   // This can only be done after the CustomActor connection has been made...
86   impl->Initialize();
87
88   return handle;
89 }
90
91 /////////////////////////////////////////////////////////////
92
93 void CanvasView::OnInitialize()
94 {
95   // CanvasView can relayout in the OnImageReady, alternative to a signal would be to have a upcall from the Control to CanvasView
96   Dali::Toolkit::Control handle(GetOwner());
97
98   DevelControl::SetAccessibilityConstructor(Self(), [](Dali::Actor actor) {
99     return std::unique_ptr<Dali::Accessibility::Accessible>(
100       new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::IMAGE));
101   });
102
103   Adaptor::Get().RegisterProcessor(*this);
104 }
105
106 void CanvasView::OnRelayout(const Vector2& size, RelayoutContainer& container)
107 {
108   if(!mCanvasRenderer ||
109      !mCanvasRenderer.SetSize(size))
110   {
111     return;
112   }
113   mSize = size;
114 }
115
116 void CanvasView::OnSizeSet(const Vector3& targetSize)
117 {
118   Control::OnSizeSet(targetSize);
119
120   if(!mCanvasRenderer ||
121      !mCanvasRenderer.SetSize(Vector2(targetSize)))
122   {
123     return;
124   }
125   mSize.width  = targetSize.width;
126   mSize.height = targetSize.height;
127 }
128
129 void CanvasView::Process(bool postProcessor)
130 {
131   if(mCanvasRenderer && mCanvasRenderer.IsCanvasChanged() && mSize.width > 0 && mSize.height > 0)
132   {
133     AddRasterizationTask();
134   }
135 }
136
137 void CanvasView::AddRasterizationTask()
138 {
139   CanvasRendererRasterizingTaskPtr newTask = new CanvasRendererRasterizingTask(this, mCanvasRenderer);
140
141   if(!mCanvasViewRasterizeThread)
142   {
143     mCanvasViewRasterizeThread = new CanvasViewRasterizeThread();
144     mCanvasViewRasterizeThread->RasterizationCompletedSignal().Connect(this, &CanvasView::ApplyRasterizedImage);
145     mCanvasViewRasterizeThread->Start();
146   }
147
148   if(mCanvasRenderer.Commit())
149   {
150     mCanvasViewRasterizeThread->AddTask(newTask);
151   }
152 }
153
154 void CanvasView::ApplyRasterizedImage(PixelData rasterizedPixelData)
155 {
156   if(rasterizedPixelData)
157   {
158     auto rasterizedPixelDataWidth  = rasterizedPixelData.GetWidth();
159     auto rasterizedPixelDataHeight = rasterizedPixelData.GetHeight();
160
161     if(rasterizedPixelDataWidth > 0 && rasterizedPixelDataHeight > 0)
162     {
163       if(!mTexture || mTexture.GetWidth() != rasterizedPixelDataWidth || mTexture.GetHeight() != rasterizedPixelDataHeight)
164       {
165         mTexture = Texture::New(TextureType::TEXTURE_2D, Dali::Pixel::RGBA8888, rasterizedPixelDataWidth, rasterizedPixelDataHeight);
166         mTexture.Upload(rasterizedPixelData);
167
168         if(!mTextureSet)
169         {
170           mTextureSet       = TextureSet::New();
171           Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
172           Shader   shader   = Shader::New(SHADER_CANVAS_VIEW_VERT, SHADER_CANVAS_VIEW_FRAG);
173           Renderer renderer = Renderer::New(geometry, shader);
174           renderer.SetTextures(mTextureSet);
175           renderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true);
176
177           Actor actor = Self();
178           if(actor)
179           {
180             actor.AddRenderer(renderer);
181           }
182         }
183         mTextureSet.SetTexture(0, mTexture);
184       }
185       else
186       {
187         //Update texture
188         mTexture.Upload(rasterizedPixelData);
189       }
190     }
191   }
192
193   //If there are accumulated changes to CanvasRenderer during Rasterize, Rasterize once again.
194   if(mCanvasRenderer && mCanvasRenderer.IsCanvasChanged())
195   {
196     AddRasterizationTask();
197   }
198 }
199
200 bool CanvasView::AddDrawable(Dali::CanvasRenderer::Drawable& drawable)
201 {
202   if(mCanvasRenderer && mCanvasRenderer.AddDrawable(drawable))
203   {
204     return true;
205   }
206   return false;
207 }
208 } // namespace Internal
209 } // namespace Toolkit
210 } // namespace Dali