Merge "Shader compilation tool for dali-toolkit" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / gaussian-blur-view / gaussian-blur-view-impl.cpp
1 /*
2  * Copyright (c) 2020 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 "gaussian-blur-view-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <sstream>
23 #include <iomanip>
24 #include <dali/public-api/animation/constraint.h>
25 #include <dali/public-api/animation/constraints.h>
26 #include <dali/devel-api/common/stage.h>
27 #include <dali/public-api/object/type-registry.h>
28 #include <dali/public-api/object/type-registry-helper.h>
29 #include <dali/public-api/rendering/geometry.h>
30 #include <dali/public-api/rendering/renderer.h>
31 #include <dali/public-api/rendering/shader.h>
32 #include <dali/public-api/render-tasks/render-task-list.h>
33 #include <dali/integration-api/debug.h>
34 #include <dali/devel-api/actors/actor-devel.h>
35
36 // INTERNAL INCLUDES
37 #include <dali-toolkit/public-api/visuals/visual-properties.h>
38 #include <dali-toolkit/internal/controls/control/control-renderers.h>
39 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
40 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
41
42 // TODO:
43 // pixel format / size - set from JSON
44 // aspect ratio property needs to be able to be constrained also for cameras, not possible currently. Therefore changing aspect ratio of GaussianBlurView won't currently work
45 // default near clip value
46 // Manager object - re-use render targets if there are multiple GaussianBlurViews created
47
48
49 /////////////////////////////////////////////////////////
50 // IMPLEMENTATION NOTES
51
52 // As the GaussianBlurView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
53 // OnSetSize() does not get called when GaussianBlurView object size is modified using a Constraint.
54 // OnSizeAnimation() only gets called once per AnimateTo/By() and if an Animation has N such calls then only the final one will end up being used. Therefore we can't use
55 // OnSizeAnimation() to alter render target sizes.
56 // To get around the above problems, we use fixed sized render targets, from the last SetSize() call (which calls OnSetSize()), then we adjust the internal cameras / actors
57 // to take account of the changed GaussianBlurView object size, projecting to the unchanged render target sizes. This is done relative to the fixed render target / actor sizes
58 // by using constraints relative to the GaussianBlurView actor size.
59
60
61 // 2 modes:
62 // 1st mode, this control has a tree of actors (use Add() to add children) that are rendered and blurred.
63 // mRenderChildrenTask renders children to FB mRenderTargetForRenderingChildren
64 // mHorizBlurTask renders mHorizBlurActor Actor showing FB mRenderTargetForRenderingChildren into FB mRenderTarget2
65 // mVertBlurTask renders mVertBlurActor Actor showing FB mRenderTarget2 into FB mRenderTarget1
66 // mCompositeTask renders mCompositingActor Actor showing FB mRenderTarget1 into FB mRenderTargetForRenderingChildren
67 //
68 // 2nd mode, an image is blurred and rendered to a supplied target framebuffer
69 // mHorizBlurTask renders mHorizBlurActor Actor showing mUserInputImage into FB mRenderTarget2
70 // mVertBlurTask renders mVertBlurActor Actor showing mRenderTarget2 into FB mUserOutputRenderTarget
71 //
72 // Only this 2nd mode handles ActivateOnce
73
74 namespace Dali
75 {
76
77 namespace Toolkit
78 {
79
80 namespace Internal
81 {
82
83 namespace
84 {
85
86 using namespace Dali;
87
88 BaseHandle Create()
89 {
90   return Toolkit::GaussianBlurView::New();
91 }
92
93 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::GaussianBlurView, Toolkit::Control, Create )
94 DALI_TYPE_REGISTRATION_END()
95
96 const unsigned int GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES = 5;
97 const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH = 1.5f;
98 const Pixel::Format GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGBA8888;
99 const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH = 1.0f;                                       // default, fully blurred
100 const char* const GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME = "GaussianBlurStrengthPropertyName";
101 const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
102 const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
103
104 const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
105
106 } // namespace
107
108
109 GaussianBlurView::GaussianBlurView()
110 : Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS ) ),
111   mNumSamples(GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES),
112   mBlurBellCurveWidth( 0.001f ),
113   mPixelFormat(GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT),
114   mDownsampleWidthScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE),
115   mDownsampleHeightScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE),
116   mDownsampledWidth( 0.0f ),
117   mDownsampledHeight( 0.0f ),
118   mBlurUserImage( false ),
119   mRenderOnce( false ),
120   mBackgroundColor( Color::BLACK ),
121   mTargetSize(Vector2::ZERO),
122   mLastSize(Vector2::ZERO),
123   mChildrenRoot(Actor::New()),
124   mInternalRoot(Actor::New()),
125   mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
126   mActivated( false )
127 {
128   SetBlurBellCurveWidth(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH);
129 }
130
131 GaussianBlurView::GaussianBlurView( const unsigned int numSamples,
132                                     const float blurBellCurveWidth,
133                                     const Pixel::Format renderTargetPixelFormat,
134                                     const float downsampleWidthScale,
135                                     const float downsampleHeightScale,
136                                     bool blurUserImage)
137 : Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS ) ),
138   mNumSamples(numSamples),
139   mBlurBellCurveWidth( 0.001f ),
140   mPixelFormat(renderTargetPixelFormat),
141   mDownsampleWidthScale(downsampleWidthScale),
142   mDownsampleHeightScale(downsampleHeightScale),
143   mDownsampledWidth( 0.0f ),
144   mDownsampledHeight( 0.0f ),
145   mBlurUserImage( blurUserImage ),
146   mRenderOnce( false ),
147   mBackgroundColor( Color::BLACK ),
148   mTargetSize(Vector2::ZERO),
149   mLastSize(Vector2::ZERO),
150   mChildrenRoot(Actor::New()),
151   mInternalRoot(Actor::New()),
152   mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
153   mActivated( false )
154 {
155   SetBlurBellCurveWidth(blurBellCurveWidth);
156 }
157
158 GaussianBlurView::~GaussianBlurView()
159 {
160 }
161
162
163 Toolkit::GaussianBlurView GaussianBlurView::New()
164 {
165   GaussianBlurView* impl = new GaussianBlurView();
166
167   Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
168
169   // Second-phase init of the implementation
170   // This can only be done after the CustomActor connection has been made...
171   impl->Initialize();
172
173   return handle;
174 }
175
176 Toolkit::GaussianBlurView GaussianBlurView::New(const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
177                                                 const float downsampleWidthScale, const float downsampleHeightScale,
178                                                 bool blurUserImage)
179 {
180   GaussianBlurView* impl = new GaussianBlurView( numSamples, blurBellCurveWidth, renderTargetPixelFormat,
181                                                  downsampleWidthScale, downsampleHeightScale,
182                                                  blurUserImage);
183
184   Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
185
186   // Second-phase init of the implementation
187   // This can only be done after the CustomActor connection has been made...
188   impl->Initialize();
189
190   return handle;
191 }
192
193 void GaussianBlurView::SetUserImageAndOutputRenderTarget(Texture inputImage, FrameBuffer outputRenderTarget)
194 {
195   // can only do this if the GaussianBlurView object was created with this parameter set
196   DALI_ASSERT_ALWAYS(mBlurUserImage);
197
198   mUserInputImage = inputImage;
199
200   SetRendererTexture( mHorizBlurActor.GetRendererAt(0), inputImage );
201
202   mUserOutputRenderTarget = outputRenderTarget;
203 }
204
205 FrameBuffer GaussianBlurView::GetBlurredRenderTarget() const
206 {
207   if(!mUserOutputRenderTarget)
208   {
209     return mRenderTargetForRenderingChildren;
210   }
211
212   return mUserOutputRenderTarget;
213 }
214
215 void GaussianBlurView::SetBackgroundColor( const Vector4& color )
216 {
217   mBackgroundColor = color;
218 }
219
220 Vector4 GaussianBlurView::GetBackgroundColor() const
221 {
222   return mBackgroundColor;
223 }
224
225 ///////////////////////////////////////////////////////////
226 //
227 // Private methods
228 //
229
230 void GaussianBlurView::OnInitialize()
231 {
232   // root actor to parent all user added actors, needed to allow us to set that subtree as exclusive for our child render task
233   mChildrenRoot.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
234   mInternalRoot.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
235
236   //////////////////////////////////////////////////////
237   // Create shaders
238
239   std::ostringstream fragmentStringStream;
240   fragmentStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
241   fragmentStringStream << SHADER_GAUSSIAN_BLUR_VIEW_FRAG;
242   std::string fragmentSource(fragmentStringStream.str());
243
244   //////////////////////////////////////////////////////
245   // Create actors
246
247   // Create an actor for performing a horizontal blur on the texture
248   mHorizBlurActor = Actor::New();
249   mHorizBlurActor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
250
251   Renderer renderer = CreateRenderer( BASIC_VERTEX_SOURCE, fragmentSource.c_str() );
252   mHorizBlurActor.AddRenderer( renderer );
253
254   // Create an actor for performing a vertical blur on the texture
255   mVertBlurActor = Actor::New();
256   mVertBlurActor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
257   renderer = CreateRenderer( BASIC_VERTEX_SOURCE, fragmentSource.c_str() );
258   mVertBlurActor.AddRenderer( renderer );
259
260   // Register a property that the user can control to fade the blur in / out via the GaussianBlurView object
261   Actor self = Self();
262   mBlurStrengthPropertyIndex = self.RegisterProperty(GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH);
263
264   // Create an image view for compositing the blur and the original child actors render
265   if(!mBlurUserImage)
266   {
267     mCompositingActor = Actor::New();
268     mCompositingActor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
269     mCompositingActor.SetProperty( Actor::Property::OPACITY,GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH); // ensure alpha is enabled for this object and set default value
270     renderer = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
271     mCompositingActor.AddRenderer( renderer );
272
273     Constraint blurStrengthConstraint = Constraint::New<float>( mCompositingActor, Actor::Property::COLOR_ALPHA, EqualToConstraint());
274     blurStrengthConstraint.AddSource( Source( self, mBlurStrengthPropertyIndex) );
275     blurStrengthConstraint.Apply();
276
277     // Create an image view for holding final result, i.e. the blurred image. This will get rendered to screen later, via default / user render task
278     mTargetActor = Actor::New();
279     mTargetActor.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
280     renderer = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
281     mTargetActor.AddRenderer( renderer );
282
283     //////////////////////////////////////////////////////
284     // Create cameras for the renders corresponding to the view size
285     mRenderFullSizeCamera = CameraActor::New();
286     mRenderFullSizeCamera.SetInvertYAxis( true );
287     mRenderFullSizeCamera.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
288
289     //////////////////////////////////////////////////////
290     // Connect to actor tree
291     mInternalRoot.Add( mCompositingActor );
292     mInternalRoot.Add( mTargetActor );
293     mInternalRoot.Add( mRenderFullSizeCamera );
294   }
295
296   //////////////////////////////////////////////////////
297   // Create camera for the renders corresponding to the (potentially downsampled) render targets' size
298   mRenderDownsampledCamera = CameraActor::New();
299   mRenderDownsampledCamera.SetInvertYAxis( true );
300   mRenderDownsampledCamera.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::CENTER );
301
302   //////////////////////////////////////////////////////
303   // Connect to actor tree
304   Self().Add( mChildrenRoot );
305   mInternalRoot.Add( mHorizBlurActor );
306   mInternalRoot.Add( mVertBlurActor );
307   mInternalRoot.Add( mRenderDownsampledCamera );
308
309   DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) {
310     return std::unique_ptr< Dali::Accessibility::Accessible >(
311       new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) );
312   } );
313 }
314
315
316 void GaussianBlurView::OnSizeSet(const Vector3& targetSize)
317 {
318   mTargetSize = Vector2(targetSize);
319
320   mChildrenRoot.SetProperty( Actor::Property::SIZE, targetSize);
321
322   if( !mBlurUserImage )
323   {
324     mCompositingActor.SetProperty( Actor::Property::SIZE, targetSize);
325     mTargetActor.SetProperty( Actor::Property::SIZE, targetSize);
326
327     // Children render camera must move when GaussianBlurView object is resized. This is since we cannot change render target size - so we need to remap the child actors' rendering
328     // accordingly so they still exactly fill the render target. Note that this means the effective resolution of the child render changes as the GaussianBlurView object changes
329     // size, this is the trade off for not being able to modify render target size
330     // Change camera z position based on GaussianBlurView actor height
331     float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
332     mRenderFullSizeCamera.SetProperty( Actor::Property::POSITION_Z, mTargetSize.height * cameraPosConstraintScale);
333   }
334
335
336   // if we have already activated the blur, need to update render target sizes now to reflect the new size of this actor
337   if(mActivated)
338   {
339     Deactivate();
340     Activate();
341   }
342
343   Control::OnSizeSet( targetSize );
344 }
345
346 void GaussianBlurView::OnChildAdd( Actor& child )
347 {
348   if( child != mChildrenRoot && child != mInternalRoot)
349   {
350     mChildrenRoot.Add( child );
351   }
352
353   Control::OnChildAdd( child );
354 }
355
356 void GaussianBlurView::OnChildRemove( Actor& child )
357 {
358   mChildrenRoot.Remove( child );
359
360   Control::OnChildRemove( child );
361 }
362
363 void GaussianBlurView::AllocateResources()
364 {
365   mLastSize = mTargetSize;
366
367   // get size of downsampled render targets
368   mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
369   mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
370
371   // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
372   mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
373   // TODO: how do we pick a reasonable value for near clip? Needs to relate to normal camera the user renders with, but we don't have a handle on it
374   mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
375   mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
376   mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
377
378   mRenderDownsampledCamera.SetProperty( Actor::Property::POSITION, Vector3(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f))));
379
380   // setup for normal operation
381   if(!mBlurUserImage)
382   {
383     // Create and place a camera for the children render, corresponding to its render target size
384     mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
385     // TODO: how do we pick a reasonable value for near clip? Needs to relate to normal camera the user renders with, but we don't have a handle on it
386     mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
387     mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
388     mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
389
390     float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
391     mRenderFullSizeCamera.SetProperty( Actor::Property::POSITION, Vector3(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale));
392
393     // create offscreen buffer of new size to render our child actors to
394     mRenderTargetForRenderingChildren = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
395     Texture texture = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
396     mRenderTargetForRenderingChildren.AttachColorTexture( texture );
397
398     // Set actor for performing a horizontal blur
399     SetRendererTexture( mHorizBlurActor.GetRendererAt(0), mRenderTargetForRenderingChildren );
400
401     // Create offscreen buffer for vert blur pass
402     mRenderTarget1 = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
403     texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
404     mRenderTarget1.AttachColorTexture( texture );
405
406     // use the completed blur in the first buffer and composite with the original child actors render
407     SetRendererTexture( mCompositingActor.GetRendererAt(0), mRenderTarget1 );
408
409     // set up target actor for rendering result, i.e. the blurred image
410     SetRendererTexture( mTargetActor.GetRendererAt(0), mRenderTargetForRenderingChildren );
411   }
412
413   // Create offscreen buffer for horiz blur pass
414   mRenderTarget2 = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
415   Texture texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
416   mRenderTarget2.AttachColorTexture( texture );
417
418   // size needs to match render target
419   mHorizBlurActor.SetProperty( Actor::Property::SIZE, Vector2(mDownsampledWidth, mDownsampledHeight) );
420
421   // size needs to match render target
422   mVertBlurActor.SetProperty( Actor::Property::SIZE, Vector2(mDownsampledWidth, mDownsampledHeight) );
423   SetRendererTexture( mVertBlurActor.GetRendererAt(0), mRenderTarget2 );
424
425   // set gaussian blur up for new sized render targets
426   SetShaderConstants();
427 }
428
429 void GaussianBlurView::CreateRenderTasks()
430 {
431   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
432
433   if(!mBlurUserImage)
434   {
435     // create render task to render our child actors to offscreen buffer
436     mRenderChildrenTask = taskList.CreateTask();
437     mRenderChildrenTask.SetSourceActor( mChildrenRoot );
438     mRenderChildrenTask.SetExclusive(true);
439     mRenderChildrenTask.SetInputEnabled( false );
440     mRenderChildrenTask.SetClearEnabled( true );
441     mRenderChildrenTask.SetClearColor( mBackgroundColor );
442
443     mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
444     mRenderChildrenTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
445
446     if( mRenderOnce )
447     {
448       mRenderChildrenTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
449     }
450   }
451
452   // perform a horizontal blur targeting the second buffer
453   mHorizBlurTask = taskList.CreateTask();
454   mHorizBlurTask.SetSourceActor( mHorizBlurActor );
455   mHorizBlurTask.SetExclusive(true);
456   mHorizBlurTask.SetInputEnabled( false );
457   mHorizBlurTask.SetClearEnabled( true );
458   mHorizBlurTask.SetClearColor( mBackgroundColor );
459   mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
460   mHorizBlurTask.SetFrameBuffer( mRenderTarget2 );
461   if( mRenderOnce || ( mRenderOnce && mBlurUserImage ) )
462   {
463     mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
464   }
465
466   // use the second buffer and perform a horizontal blur targeting the first buffer
467   mVertBlurTask = taskList.CreateTask();
468   mVertBlurTask.SetSourceActor( mVertBlurActor );
469   mVertBlurTask.SetExclusive(true);
470   mVertBlurTask.SetInputEnabled( false );
471   mVertBlurTask.SetClearEnabled( true );
472   mVertBlurTask.SetClearColor( mBackgroundColor );
473   mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
474   if(mUserOutputRenderTarget)
475   {
476     mVertBlurTask.SetFrameBuffer( mUserOutputRenderTarget );
477   }
478   else
479   {
480     mVertBlurTask.SetFrameBuffer( mRenderTarget1 );
481   }
482   if( mRenderOnce || ( mRenderOnce && mBlurUserImage ) )
483   {
484     mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
485     mVertBlurTask.FinishedSignal().Connect( this, &GaussianBlurView::OnRenderTaskFinished );
486   }
487
488   // use the completed blur in the first buffer and composite with the original child actors render
489   if(!mBlurUserImage)
490   {
491     mCompositeTask = taskList.CreateTask();
492     mCompositeTask.SetSourceActor( mCompositingActor );
493     mCompositeTask.SetExclusive(true);
494     mCompositeTask.SetInputEnabled( false );
495
496     mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
497     mCompositeTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
498
499     if( mRenderOnce )
500     {
501       mCompositeTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
502     }
503   }
504 }
505
506 void GaussianBlurView::RemoveRenderTasks()
507 {
508   RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
509
510   taskList.RemoveTask(mRenderChildrenTask);
511   taskList.RemoveTask(mHorizBlurTask);
512   taskList.RemoveTask(mVertBlurTask);
513   taskList.RemoveTask(mCompositeTask);
514 }
515
516 void GaussianBlurView::Activate()
517 {
518   if( !mActivated )
519   {
520     // make sure resources are allocated and start the render tasks processing
521     Self().Add( mInternalRoot );
522     AllocateResources();
523     CreateRenderTasks();
524     mActivated = true;
525   }
526 }
527
528 void GaussianBlurView::ActivateOnce()
529 {
530   Deactivate();
531   mRenderOnce = true;
532   Activate();
533 }
534
535 void GaussianBlurView::Deactivate()
536 {
537   if( mActivated )
538   {
539     // stop render tasks processing
540     // Note: render target resources are automatically freed since we set the Image::Unused flag
541     mInternalRoot.Unparent();
542     mRenderTargetForRenderingChildren.Reset();
543     mRenderTarget1.Reset();
544     mRenderTarget2.Reset();
545     RemoveRenderTasks();
546     mRenderOnce = false;
547     mActivated = false;
548   }
549 }
550
551 void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
552 {
553   // a value of zero leads to undefined Gaussian weights, do not allow user to do this
554   mBlurBellCurveWidth = std::max( blurBellCurveWidth, 0.001f );
555 }
556
557 float GaussianBlurView::CalcGaussianWeight(float x)
558 {
559   return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
560 }
561
562 void GaussianBlurView::SetShaderConstants()
563 {
564   Vector2 *uvOffsets;
565   float ofs;
566   float *weights;
567   float w, totalWeights;
568   unsigned int i;
569
570   uvOffsets = new Vector2[mNumSamples + 1];
571   weights = new float[mNumSamples + 1];
572
573   totalWeights = weights[0] = CalcGaussianWeight(0);
574   uvOffsets[0].x = 0.0f;
575   uvOffsets[0].y = 0.0f;
576
577   for(i=0; i<mNumSamples >> 1; i++)
578   {
579     w = CalcGaussianWeight((float)(i + 1));
580     weights[(i << 1) + 1] = w;
581     weights[(i << 1) + 2] = w;
582     totalWeights += w * 2.0f;
583
584     // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
585     ofs = ((float)(i << 1)) + 1.5f;
586
587     // get offsets from units of pixels into uv coordinates in [0..1]
588     float ofsX = ofs / mDownsampledWidth;
589     float ofsY = ofs / mDownsampledHeight;
590     uvOffsets[(i << 1) + 1].x = ofsX;
591     uvOffsets[(i << 1) + 1].y = ofsY;
592
593     uvOffsets[(i << 1) + 2].x = -ofsX;
594     uvOffsets[(i << 1) + 2].y = -ofsY;
595   }
596
597   for(i=0; i<mNumSamples; i++)
598   {
599     weights[i] /= totalWeights;
600   }
601
602   // set shader constants
603   Vector2 xAxis(1.0f, 0.0f);
604   Vector2 yAxis(0.0f, 1.0f);
605   for (i = 0; i < mNumSamples; ++i )
606   {
607     mHorizBlurActor.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * xAxis );
608     mHorizBlurActor.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
609
610     mVertBlurActor.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * yAxis );
611     mVertBlurActor.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
612   }
613
614   delete[] uvOffsets;
615   delete[] weights;
616 }
617
618 std::string GaussianBlurView::GetSampleOffsetsPropertyName( unsigned int index ) const
619 {
620   DALI_ASSERT_ALWAYS( index < mNumSamples );
621
622   std::ostringstream oss;
623   oss << "uSampleOffsets[" << index << "]";
624   return oss.str();
625 }
626
627 std::string GaussianBlurView::GetSampleWeightsPropertyName( unsigned int index ) const
628 {
629   DALI_ASSERT_ALWAYS( index < mNumSamples );
630
631   std::ostringstream oss;
632   oss << "uSampleWeights[" << index << "]";
633   return oss.str();
634 }
635
636 Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
637 {
638   return mFinishedSignal;
639 }
640
641 void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
642 {
643   Toolkit::GaussianBlurView handle( GetOwner() );
644   mFinishedSignal.Emit( handle );
645 }
646
647 } // namespace Internal
648 } // namespace Toolkit
649 } // namespace Dali