2 * Copyright (c) 2022 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 <dali-toolkit/dali-toolkit.h>
20 #include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
21 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/trace.h>
31 #include "shared/utility.h"
34 using namespace Dali::Toolkit;
39 enum class ControlTestType
42 COLOR = 0, ///< Test with simple color
43 IMAGE, ///< Test with simple image
44 TEXT, ///< Test with simple text label
45 ROUNDED_COLOR, ///< Test with rounded color
46 BORDER_COLOR, ///< Test with borderline color
47 ROUNDED_BORDER_COLOR, ///< Test with rounded borderline color
48 BLUR_COLOR, ///< Test with blur color
49 ROUNDED_BLUR_COLOR, ///< Test with rounded blur color
54 const char* TestTypeString(ControlTestType type)
59 case ControlTestType::COLOR: return "COLOR";
60 case ControlTestType::IMAGE: return "IMAGE";
61 case ControlTestType::TEXT: return "TEXT";
62 case ControlTestType::ROUNDED_COLOR: return "ROUNDED COLOR";
63 case ControlTestType::BORDER_COLOR: return "BORDER COLOR";
64 case ControlTestType::ROUNDED_BORDER_COLOR:return "ROUNDED BORDER COLOR";
65 case ControlTestType::BLUR_COLOR: return "BLUR COLOR";
66 case ControlTestType::ROUNDED_BLUR_COLOR: return "ROUNDED BLUR COLOR";
67 default: return "UNKNOWN";
72 // NOTE : Due to the image load is bottleneck on target, we just use single small image.
73 const char* IMAGE_PATH[] = {
74 DEMO_IMAGE_DIR "gallery-small-1.jpg",
77 constexpr uint32_t NUM_IMAGES = sizeof(IMAGE_PATH) / sizeof(char*);
79 constexpr uint32_t ROWS_COUNT(40);
80 constexpr uint32_t COLUMNS_COUNT(40);
81 constexpr uint32_t TOTAL_COLUMNS_COUNT(80);
82 constexpr uint32_t DURATION_PER_COLUMNS(50); // miliseconds.
83 // Increase animation time cause OnTick time can be delayed.
84 constexpr uint32_t DURATION_OF_ANIMATION(DURATION_PER_COLUMNS*(COLUMNS_COUNT * 4 / 3)); // miliseconds.
86 // We should render same type of views in some timing.
87 static_assert(COLUMNS_COUNT * 2 <= TOTAL_COLUMNS_COUNT);
89 constexpr float VIEW_MARGIN_RATE = 0.2f;
91 // copy from dali-adaptor time-service.cpp
92 void GetNanoseconds(uint64_t& timeInNanoseconds)
94 // Get the time of a monotonic clock since its epoch.
95 auto epoch = std::chrono::steady_clock::now().time_since_epoch();
97 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(epoch);
99 timeInNanoseconds = static_cast<uint64_t>(duration.count());
102 Control CreateColor()
104 Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
105 bgView.SetBackgroundColor(Color::YELLOW);
109 Control CreateImage(uint32_t& imageCount)
111 Control bgView = ImageView::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS, IMAGE_PATH[imageCount++ % NUM_IMAGES]);
115 Control CreateTextLabel()
117 Control bgView = TextLabel::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS, "Hello, World!");
121 Control CreateRoundedColor()
123 Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
126 map[Visual::Property::TYPE] = Visual::COLOR;
127 map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW;
128 map[DevelVisual::Property::CORNER_RADIUS] = 0.5f;
129 map[DevelVisual::Property::CORNER_RADIUS_POLICY] = Visual::Transform::Policy::RELATIVE;
131 bgView[Control::Property::BACKGROUND] = map;
136 Control CreateBorderColor(const float& requiredBorderlineWidth)
138 Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
141 map[Visual::Property::TYPE] = Visual::COLOR;
142 map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW;
143 map[DevelVisual::Property::BORDERLINE_WIDTH] = requiredBorderlineWidth;
144 map[DevelVisual::Property::BORDERLINE_COLOR] = Color::RED;
146 bgView[Control::Property::BACKGROUND] = map;
151 Control CreateRoundedBorderColor(const float& requiredBorderlineWidth)
153 Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
156 map[Visual::Property::TYPE] = Visual::COLOR;
157 map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW;
158 map[DevelVisual::Property::CORNER_RADIUS] = 0.5f;
159 map[DevelVisual::Property::CORNER_RADIUS_POLICY] = Visual::Transform::Policy::RELATIVE;
160 map[DevelVisual::Property::BORDERLINE_WIDTH] = requiredBorderlineWidth;
161 map[DevelVisual::Property::BORDERLINE_COLOR] = Color::RED;
163 bgView[Control::Property::BACKGROUND] = map;
168 Control CreateBlurColor(const float& requiredBlurRadius)
170 Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
173 map[Visual::Property::TYPE] = Visual::COLOR;
174 map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW;
175 map[DevelColorVisual::Property::BLUR_RADIUS] = requiredBlurRadius;
177 bgView[Control::Property::BACKGROUND] = map;
182 Control CreateRoundedBlurColor(const float& requiredBlurRadius)
184 Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
187 map[Visual::Property::TYPE] = Visual::COLOR;
188 map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW;
189 map[DevelVisual::Property::CORNER_RADIUS] = 0.5f;
190 map[DevelVisual::Property::CORNER_RADIUS_POLICY] = Visual::Transform::Policy::RELATIVE;
191 map[DevelColorVisual::Property::BLUR_RADIUS] = requiredBlurRadius;
193 bgView[Control::Property::BACKGROUND] = map;
199 * @brief Statistic container that we can get average / sum / min/ max.
201 * @tparam T Type of data. T should define add, compare, div-by-int, numeric_limits<T>::min and max
206 static constexpr double trimRate = 0.34;
223 vmax = std::numeric_limits<T>::min();
224 vmin = std::numeric_limits<T>::max();
232 vmax = std::max(vmax, x);
233 vmin = std::min(vmin, x);
238 if(vcnt == 0) return 0.0;
239 return static_cast<double>(vsum) / vcnt;
242 double GetTrimedAverage()
244 if(vcnt == 0) return 0.0;
245 std::sort(v.begin(), v.end());
247 int removedCnt = static_cast<int>(vcnt * trimRate * 0.5); // floor
248 int trimVcnt = vcnt - removedCnt * 2;
254 for(int i = removedCnt; i < vcnt - removedCnt; i++)
259 return static_cast<double>(trimVsum) / trimVcnt;
263 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERF_VIEW_CREATION_SAMPLE, true);
268 * Test application to compare performance between various type of Views creation time & manually created Renderers
270 class PerfViewCreation : public ConnectionTracker
273 PerfViewCreation(Application& application)
274 : mApplication(application),
275 mRowsCount(ROWS_COUNT),
276 mColumnsCount(COLUMNS_COUNT),
277 mTotalColumnsCount(TOTAL_COLUMNS_COUNT),
278 mDurationPerColumns(DURATION_PER_COLUMNS),
279 mDurationOfAnimation(DURATION_OF_ANIMATION),
280 mTestType(ControlTestType::COLOR)
282 // Connect to the Application's Init signal
283 mApplication.InitSignal().Connect(this, &PerfViewCreation::Create);
286 ~PerfViewCreation() = default;
288 // The Init signal is received once (only) during the Application lifetime
289 void Create(Application& application)
291 GetNanoseconds(mAppStartTime);
293 // Get a handle to the window
294 mWindow = application.GetWindow();
295 mWindow.SetBackgroundColor(Color::WHITE);
296 mWindowSize = mWindow.GetSize();
298 mWindow.GetRootLayer().SetProperty(Layer::Property::DEPTH_TEST, false);
300 mSize = Vector3(mWindowSize.x / mColumnsCount, mWindowSize.y / mRowsCount, 0.0f);
302 Timer timer = Timer::New(mDurationPerColumns);
303 timer.TickSignal().Connect(this, &PerfViewCreation::OnTick);
304 mTimerList.push_back(timer);
306 mCreationStatistic.Clear();
314 // Respond to key events
315 mWindow.KeyEventSignal().Connect(this, &PerfViewCreation::OnKeyEvent);
321 if(mCreateCount < mColumnsCount)
324 Timer timer = Timer::New(mDurationPerColumns);
325 timer.TickSignal().Connect(this, &PerfViewCreation::OnTick);
326 mTimerList.push_back(timer);
332 void CreateColumnView()
337 GetNanoseconds(startTime);
338 DALI_TRACE_BEGIN(gTraceFilter, "DALI_SAMPLE_PERF_VIEW_CREATION");
340 Control columnView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
341 columnView.SetBackgroundColor(Color::BLUE);
342 columnView[Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_LEFT;
343 columnView[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_LEFT;
344 columnView[Actor::Property::SIZE] = Vector2(mSize.x, (float)mWindowSize.y);
345 columnView[Actor::Property::POSITION] = Vector2(mSize.x * (mCreateCount % mColumnsCount), -(float)mWindowSize.y);
346 for(uint32_t i = 0; i < mRowsCount; ++i)
351 case ControlTestType::COLOR:
354 bgView = CreateColor();
357 case ControlTestType::IMAGE:
359 bgView = CreateImage(mImageCount);
362 case ControlTestType::TEXT:
364 bgView = CreateTextLabel();
367 case ControlTestType::ROUNDED_COLOR:
369 bgView = CreateRoundedColor();
372 case ControlTestType::BORDER_COLOR:
374 bgView = CreateBorderColor(std::min(mSize.x, mSize.y) * VIEW_MARGIN_RATE);
377 case ControlTestType::ROUNDED_BORDER_COLOR:
379 bgView = CreateRoundedBorderColor(std::min(mSize.x, mSize.y) * VIEW_MARGIN_RATE);
382 case ControlTestType::BLUR_COLOR:
384 bgView = CreateBlurColor(std::min(mSize.x, mSize.y) * VIEW_MARGIN_RATE * 0.5f);
387 case ControlTestType::ROUNDED_BLUR_COLOR:
389 bgView = CreateRoundedBlurColor(std::min(mSize.x, mSize.y) * VIEW_MARGIN_RATE * 0.5f);
394 bgView[Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_LEFT;
395 bgView[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_LEFT;
396 bgView[Actor::Property::SIZE] = Vector2(mSize.x * (1.0f - VIEW_MARGIN_RATE), mSize.y * (1.0f - VIEW_MARGIN_RATE));
397 bgView[Actor::Property::POSITION] = Vector2(mSize.x * VIEW_MARGIN_RATE * 0.5f, mSize.y * VIEW_MARGIN_RATE * 0.5f + mSize.y * i);
398 columnView.Add(bgView);
401 mWindow.GetRootLayer().Add(columnView);
402 mCreatingControlList.push_back(columnView);
404 // Add appearing animation
405 Animation appearingAnimation = Animation::New(mDurationOfAnimation * 0.001f);
406 appearingAnimation.AnimateTo(Property(columnView, Actor::Property::POSITION_Y), 0.0f);
407 appearingAnimation.FinishedSignal().Connect(this, &PerfViewCreation::OnAppearAnimationFinished);
408 appearingAnimation.Play();
410 mCreatingAnimationList.push_back(appearingAnimation);
412 GetNanoseconds(endTime);
414 DALI_TRACE_END(gTraceFilter, "DALI_SAMPLE_PERF_VIEW_CREATION");
416 // Append duration of creation time.
417 mCreationStatistic.Add((endTime - startTime) / 1000000.0);
421 if(mCreateCount % mTotalColumnsCount == 0)
423 DALI_LOG_ERROR("Average of creation %d DALI(%s) : %.6lf ms\n", mRowsCount, TestTypeString(mTestType), mCreationStatistic.GetTrimedAverage());
424 mCreationStatistic.Clear();
425 mTestType = static_cast<ControlTestType>((static_cast<int>(mTestType) + 1) % static_cast<int>(ControlTestType::TYPE_MAX));
429 bool OnTouch(Actor actor, const TouchEvent& touch)
431 // quit the application
436 void OnKeyEvent(const KeyEvent& event)
438 if(event.GetState() == KeyEvent::DOWN)
440 if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
447 void OnAppearAnimationFinished(Animation& animation)
449 // We can assume that front of mControlList must be disappearing.
450 auto currentControl = mCreatingControlList.front();
451 mCreatingControlList.pop_front();
453 // Dereference timer safety
454 if(!mTimerList.empty())
456 mTimerList.pop_front();
459 // Dereference animation safety
460 mCreatingAnimationList.pop_back();
462 mRemovingControlList.push_back(currentControl);
464 if(mCreateCount < mTotalColumnsCount * (static_cast<int>(ControlTestType::TYPE_MAX)))
469 // Add disappearing animation
470 Animation disappearingAnimation = Animation::New(mDurationOfAnimation * 0.001f);
471 disappearingAnimation.AnimateTo(Property(currentControl, Actor::Property::POSITION_Y), (float)mWindowSize.y);
472 disappearingAnimation.FinishedSignal().Connect(this, &PerfViewCreation::OnDisappearAnimationFinished);
473 disappearingAnimation.Play();
475 mRemovingAnimationList.push_back(disappearingAnimation);
477 void OnDisappearAnimationFinished(Animation& animation)
479 // We can assume that front of mControlList must be deleted.
480 mRemovingControlList.front().Unparent();
481 mRemovingControlList.pop_front();
483 // Dereference animation safety
484 mRemovingAnimationList.pop_back();
488 // If all controls are deleted, quit this application. byebye~
489 if(mDeleteCount == mTotalColumnsCount * (static_cast<int>(ControlTestType::TYPE_MAX)))
491 GetNanoseconds(mAppEndTime);
493 DALI_LOG_ERROR("Duration of all app running time : %.6lf ms\n", (mAppEndTime - mAppStartTime) / 1000000.0);
499 Application& mApplication;
503 std::list<Control> mCreatingControlList;
504 std::list<Control> mRemovingControlList;
505 std::list<Animation> mCreatingAnimationList;
506 std::list<Animation> mRemovingAnimationList;
507 std::list<Timer> mTimerList;
511 const uint32_t mRowsCount;
512 const uint32_t mColumnsCount;
513 const uint32_t mTotalColumnsCount;
515 const uint32_t mDurationPerColumns;
516 const uint32_t mDurationOfAnimation;
518 ControlTestType mTestType;
520 uint32_t mCreateCount = 0;
521 uint32_t mDeleteCount = 0;
522 uint32_t mImageCount = 0;
524 uint64_t mAppStartTime = 0;
525 uint64_t mAppEndTime = 0;
527 Statistic<double> mCreationStatistic;
530 int DALI_EXPORT_API main(int argc, char** argv)
532 Application application = Application::New(&argc, &argv);
534 PerfViewCreation test(application);
535 application.MainLoop();