2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "blur-two-pass-filter.h"
22 #include <dali/devel-api/common/stage.h>
23 #include <dali/public-api/animation/constraints.h>
24 #include <dali/public-api/object/property-map.h>
25 #include <dali/public-api/render-tasks/render-task-list.h>
26 #include <dali/public-api/rendering/renderer.h>
30 #include <dali-toolkit/internal/controls/control/control-renderers.h>
31 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
41 const float DEFAULT_KERNEL0[] = {12.0f / 16.0f, 2.0f / 16.0f, 2.0f / 16.0f};
43 const float DEFAULT_KERNEL1[] = {8.0f / 16.0f, 2.75f / 16.0f, 2.75f / 16.0f, 1.25f / 16.0f, 1.25f / 16.0f};
45 const float DEFAULT_KERNEL2[] = {5.0f / 16.0f, 2.75f / 16.0f, 2.75f / 16.0f, 1.75f / 16.0f, 1.75f / 16.0f, 1.5f / 16.0f, 1.5f / 16.0f};
47 const float DEFAULT_KERNEL3[] = {3.0f / 16.0f, 2.0f / 16.0f, 2.0f / 16.0f, 2.0f / 16.0f, 2.0f / 16.0f, 2.0f / 16.0f, 2.0f / 16.0f, 0.5f / 16.0f, 0.5f / 16.0f};
49 const float DEFAULT_KERNEL4[] = {2.0f / 16.0f, 1.5f / 16.0f, 1.5f / 16.0f, 1.5f / 16.0f, 1.5f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f, 0.5f / 16.0f, 0.5f / 16.0f, 0.5f / 16.0f, 0.5f / 16.0f};
51 std::string GetOffsetUniformName(int index)
53 std::ostringstream oss;
54 oss << "uSampleOffsets[" << index << "]";
58 std::string GetWeightUniformName(int index)
60 std::ostringstream oss;
61 oss << "uSampleWeights[" << index << "]";
65 const char* const BLUR_STRENGTH_UNIFORM_NAME("uBlurStrength");
66 const char* const EFFECT_IMAGE_NAME("sEffect");
70 BlurTwoPassFilter::BlurTwoPassFilter()
73 // create blending actor and register the property in constructor
74 // to make sure that GetBlurStrengthPropertyIndex() always returns a valid index
75 mActorForBlending = Actor::New();
76 mBlurStrengthPropertyIndex = mActorForBlending.RegisterProperty(BLUR_STRENGTH_UNIFORM_NAME, 1.f);
79 BlurTwoPassFilter::~BlurTwoPassFilter()
83 void BlurTwoPassFilter::Enable()
85 // create custom shader effect
88 CreateKernel(DEFAULT_KERNEL4, sizeof(DEFAULT_KERNEL4) / sizeof(DEFAULT_KERNEL4[0]));
90 int kernelSize(static_cast<int>(GetKernelSize()));
92 // Set up blur-two-pass custom shader
93 std::ostringstream sstream;
94 sstream << "#define NUM_SAMPLES " << kernelSize << "\n";
95 sstream << SHADER_BLUR_TWO_PASS_SHADER_FRAG;
96 std::string fragmentSource(sstream.str());
98 // create actor to render input with applied emboss effect
99 mActorForInput = Actor::New();
100 mActorForInput.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
101 mActorForInput.SetProperty(Actor::Property::SIZE, mTargetSize);
102 Renderer rendererForInput = CreateRenderer(BASIC_VERTEX_SOURCE, fragmentSource.c_str());
103 SetRendererTexture(rendererForInput, mInputTexture);
104 mActorForInput.AddRenderer(rendererForInput);
106 // create internal offscreen for result of horizontal pass
107 mFrameBufferForHorz = FrameBuffer::New(mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE);
108 Texture textureForHorz = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height));
109 mFrameBufferForHorz.AttachColorTexture(textureForHorz);
111 // create an actor to render mImageForHorz for vertical blur pass
112 mActorForHorz = Actor::New();
113 mActorForHorz.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
114 mActorForHorz.SetProperty(Actor::Property::SIZE, mTargetSize);
115 Renderer rendererForHorz = CreateRenderer(BASIC_VERTEX_SOURCE, fragmentSource.c_str());
116 SetRendererTexture(rendererForHorz, textureForHorz);
117 mActorForHorz.AddRenderer(rendererForHorz);
119 // create internal offscreen for result of the two pass blurred image
120 mBlurredFrameBuffer = FrameBuffer::New(mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE);
121 Texture blurredTexture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height));
122 mBlurredFrameBuffer.AttachColorTexture(blurredTexture);
124 // create an actor to blend the blurred image and the input image with the given blur strength
125 Renderer rendererForBlending = CreateRenderer(BASIC_VERTEX_SOURCE, SHADER_BLUR_TWO_IMAGES_SHADER_FRAG);
126 TextureSet textureSetForBlending = rendererForBlending.GetTextures();
127 textureSetForBlending.SetTexture(0u, blurredTexture);
128 textureSetForBlending.SetTexture(1u, mInputTexture);
129 mActorForBlending.AddRenderer(rendererForBlending);
130 mActorForBlending.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
131 mActorForBlending.SetProperty(Actor::Property::SIZE, mTargetSize);
133 for(int i = 0; i < kernelSize; ++i)
135 const std::string offsetUniform(GetOffsetUniformName(i));
136 const std::string weightUniform(GetWeightUniformName(i));
138 mActorForInput.RegisterProperty(offsetUniform, Vector2(mKernel[i]) * Vector2::XAXIS);
139 mActorForInput.RegisterProperty(weightUniform, mKernel[i].z);
141 mActorForHorz.RegisterProperty(offsetUniform, Vector2(mKernel[i]) * Vector2::YAXIS);
142 mActorForHorz.RegisterProperty(weightUniform, mKernel[i].z);
145 mRootActor.Add(mActorForInput);
146 mRootActor.Add(mActorForHorz);
147 mRootActor.Add(mActorForBlending);
153 void BlurTwoPassFilter::Disable()
159 mRootActor.Remove(mCameraActor);
160 mCameraActor.Reset();
165 mRootActor.Remove(mActorForInput);
166 mActorForInput.Reset();
171 mRootActor.Remove(mActorForHorz);
172 mActorForHorz.Reset();
175 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
177 if(mRenderTaskForHorz)
179 taskList.RemoveTask(mRenderTaskForHorz);
181 if(mRenderTaskForVert)
183 taskList.RemoveTask(mRenderTaskForVert);
185 if(mRenderTaskForBlending)
187 taskList.RemoveTask(mRenderTaskForBlending);
194 void BlurTwoPassFilter::Refresh()
196 if(mRenderTaskForHorz)
198 mRenderTaskForHorz.SetRefreshRate(mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS);
201 if(mRenderTaskForVert)
203 mRenderTaskForVert.SetRefreshRate(mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS);
206 if(mRenderTaskForBlending)
208 mRenderTaskForBlending.SetRefreshRate(mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS);
212 void BlurTwoPassFilter::SetSize(const Vector2& size)
217 mActorForInput.SetProperty(Actor::Property::SIZE, mTargetSize);
221 mActorForHorz.SetProperty(Actor::Property::SIZE, mTargetSize);
223 if(mActorForBlending)
225 mActorForBlending.SetProperty(Actor::Property::SIZE, mTargetSize);
229 Handle BlurTwoPassFilter::GetHandleForAnimateBlurStrength()
231 return mActorForBlending;
234 void BlurTwoPassFilter::CreateRenderTasks()
236 RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
238 // perform a horizontal blur targeting the internal buffer
239 mRenderTaskForHorz = taskList.CreateTask();
240 mRenderTaskForHorz.SetRefreshRate(mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS);
241 mRenderTaskForHorz.SetSourceActor(mActorForInput);
242 mRenderTaskForHorz.SetExclusive(true);
243 mRenderTaskForHorz.SetInputEnabled(false);
244 mRenderTaskForHorz.SetClearEnabled(true);
245 mRenderTaskForHorz.SetClearColor(mBackgroundColor);
246 mRenderTaskForHorz.SetFrameBuffer(mFrameBufferForHorz);
247 mRenderTaskForHorz.SetCameraActor(mCameraActor);
249 // use the internal buffer and perform a horizontal blur targeting the output buffer
250 mRenderTaskForVert = taskList.CreateTask();
251 mRenderTaskForVert.SetRefreshRate(mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS);
252 mRenderTaskForVert.SetSourceActor(mActorForHorz);
253 mRenderTaskForVert.SetExclusive(true);
254 mRenderTaskForVert.SetInputEnabled(false);
255 mRenderTaskForVert.SetClearEnabled(true);
256 mRenderTaskForVert.SetClearColor(mBackgroundColor);
257 mRenderTaskForVert.SetFrameBuffer(mBlurredFrameBuffer);
258 mRenderTaskForVert.SetCameraActor(mCameraActor);
260 //Perform a blending between the blurred image and the input image
261 mRenderTaskForBlending = taskList.CreateTask();
262 mRenderTaskForBlending.SetRefreshRate(mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS);
263 mRenderTaskForBlending.SetSourceActor(mActorForBlending);
264 mRenderTaskForBlending.SetExclusive(true);
265 mRenderTaskForBlending.SetInputEnabled(false);
266 mRenderTaskForBlending.SetClearEnabled(true);
267 mRenderTaskForBlending.SetClearColor(mBackgroundColor);
268 mRenderTaskForBlending.SetFrameBuffer(mOutputFrameBuffer);
269 mRenderTaskForBlending.SetCameraActor(mCameraActor);
272 } // namespace Internal
274 } // namespace Toolkit