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;
37 // TODO : borderline, blur type need to solve partial update issue.
38 // Until that issue exist, just block it.
39 #define ALLOW_BORDER_AND_BLUR 0
43 enum class ControlTestType
46 COLOR = 0, ///< Test with simple color
47 IMAGE, ///< Test with simple image
48 TEXT, ///< Test with simple text label
49 ROUNDED_COLOR, ///< Test with rounded color
50 #if ALLOW_BORDER_AND_BLUR
51 BORDER_COLOR, ///< Test with borderline color
52 ROUNDED_BORDER_COLOR, ///< Test with rounded borderline color
53 BLUR_COLOR, ///< Test with blur color
54 ROUNDED_BLUR_COLOR, ///< Test with blur color
60 const char* TestTypeString(ControlTestType type)
65 case ControlTestType::COLOR: return "COLOR";
66 case ControlTestType::IMAGE: return "IMAGE";
67 case ControlTestType::TEXT: return "TEXT";
68 case ControlTestType::ROUNDED_COLOR: return "ROUNDED COLOR";
69 #if ALLOW_BORDER_AND_BLUR
70 case ControlTestType::BORDER_COLOR: return "BORDER COLOR";
71 case ControlTestType::ROUNDED_BORDER_COLOR:return "ROUNDED BORDER COLOR";
72 case ControlTestType::BLUR_COLOR: return "BLUR COLOR";
73 case ControlTestType::ROUNDED_BLUR_COLOR: return "ROUNDED BLUR COLOR";
75 default: return "UNKNOWN";
80 // NOTE : Due to the image load is bottleneck on target, we just use single small image.
81 const char* IMAGE_PATH[] = {
82 DEMO_IMAGE_DIR "gallery-small-1.jpg",
85 constexpr uint32_t NUM_IMAGES = sizeof(IMAGE_PATH) / sizeof(char*);
87 constexpr uint32_t ROWS_COUNT(40);
88 constexpr uint32_t COLUMNS_COUNT(40);
89 constexpr uint32_t TOTAL_COLUMNS_COUNT(80);
90 constexpr uint32_t DURATION_PER_COLUMNS(50); // miliseconds.
91 // Increase animation time cause OnTick time can be delayed.
92 constexpr uint32_t DURATION_OF_ANIMATION(DURATION_PER_COLUMNS*(COLUMNS_COUNT * 4 / 3)); // miliseconds.
94 // We should render same type of views in some timing.
95 static_assert(COLUMNS_COUNT * 2 <= TOTAL_COLUMNS_COUNT);
97 constexpr float VIEW_MARGIN_RATE = 0.1f;
99 // copy from dali-adaptor time-service.cpp
100 void GetNanoseconds(uint64_t& timeInNanoseconds)
102 // Get the time of a monotonic clock since its epoch.
103 auto epoch = std::chrono::steady_clock::now().time_since_epoch();
105 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(epoch);
107 timeInNanoseconds = static_cast<uint64_t>(duration.count());
110 Control CreateColor()
112 Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
113 bgView.SetBackgroundColor(Color::YELLOW);
117 Control CreateImage(uint32_t& imageCount)
119 Control bgView = ImageView::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS, IMAGE_PATH[imageCount++ % NUM_IMAGES]);
123 Control CreateTextLabel()
125 Control bgView = TextLabel::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS, "Hello, World!");
129 Control CreateRoundedColor()
131 Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
134 map[Visual::Property::TYPE] = Visual::COLOR;
135 map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW;
136 map[DevelVisual::Property::CORNER_RADIUS] = 0.5f;
137 map[DevelVisual::Property::CORNER_RADIUS_POLICY] = Visual::Transform::Policy::RELATIVE;
139 bgView[Control::Property::BACKGROUND] = map;
144 #if ALLOW_BORDER_AND_BLUR
145 Control CreateBorderColor(const float& requiredBorderlineWidth)
147 Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
150 map[Visual::Property::TYPE] = Visual::COLOR;
151 map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW;
152 map[DevelVisual::Property::BORDERLINE_WIDTH] = requiredBorderlineWidth;
153 map[DevelVisual::Property::BORDERLINE_COLOR] = Color::RED;
155 bgView[Control::Property::BACKGROUND] = map;
160 Control CreateRoundedBorderColor(const float& requiredBorderlineWidth)
162 Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
165 map[Visual::Property::TYPE] = Visual::COLOR;
166 map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW;
167 map[DevelVisual::Property::CORNER_RADIUS] = 0.5f;
168 map[DevelVisual::Property::CORNER_RADIUS_POLICY] = Visual::Transform::Policy::RELATIVE;
169 map[DevelVisual::Property::BORDERLINE_WIDTH] = requiredBorderlineWidth;
170 map[DevelVisual::Property::BORDERLINE_COLOR] = Color::RED;
172 bgView[Control::Property::BACKGROUND] = map;
177 Control CreateBlurColor(const float& requiredBlurRadius)
179 Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
182 map[Visual::Property::TYPE] = Visual::COLOR;
183 map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW;
184 map[DevelColorVisual::Property::BLUR_RADIUS] = requiredBlurRadius;
186 bgView[Control::Property::BACKGROUND] = map;
191 Control CreateRoundedBlurColor(const float& requiredBlurRadius)
193 Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
196 map[Visual::Property::TYPE] = Visual::COLOR;
197 map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW;
198 map[DevelVisual::Property::CORNER_RADIUS] = 0.5f;
199 map[DevelVisual::Property::CORNER_RADIUS_POLICY] = Visual::Transform::Policy::RELATIVE;
200 map[DevelColorVisual::Property::BLUR_RADIUS] = requiredBlurRadius;
202 bgView[Control::Property::BACKGROUND] = map;
209 * @brief Statistic container that we can get average / sum / min/ max.
211 * @tparam T Type of data. T should define add, compare, div-by-int, numeric_limits<T>::min and max
216 static constexpr double trimRate = 0.34;
233 vmax = std::numeric_limits<T>::min();
234 vmin = std::numeric_limits<T>::max();
242 vmax = std::max(vmax, x);
243 vmin = std::min(vmin, x);
248 if(vcnt == 0) return 0.0;
249 return static_cast<double>(vsum) / vcnt;
252 double GetTrimedAverage()
254 if(vcnt == 0) return 0.0;
255 std::sort(v.begin(), v.end());
257 int removedCnt = static_cast<int>(vcnt * trimRate * 0.5); // floor
258 int trimVcnt = vcnt - removedCnt * 2;
264 for(int i = removedCnt; i < vcnt - removedCnt; i++)
269 return static_cast<double>(trimVsum) / trimVcnt;
273 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERF_VIEW_CREATION_SAMPLE, true);
278 * Test application to compare performance between various type of Views creation time & manually created Renderers
280 class PerfViewCreation : public ConnectionTracker
283 PerfViewCreation(Application& application)
284 : mApplication(application),
285 mRowsCount(ROWS_COUNT),
286 mColumnsCount(COLUMNS_COUNT),
287 mTotalColumnsCount(TOTAL_COLUMNS_COUNT),
288 mDurationPerColumns(DURATION_PER_COLUMNS),
289 mDurationOfAnimation(DURATION_OF_ANIMATION),
290 mTestType(ControlTestType::COLOR)
292 // Connect to the Application's Init signal
293 mApplication.InitSignal().Connect(this, &PerfViewCreation::Create);
296 ~PerfViewCreation() = default;
298 // The Init signal is received once (only) during the Application lifetime
299 void Create(Application& application)
301 GetNanoseconds(mAppStartTime);
303 // Get a handle to the window
304 mWindow = application.GetWindow();
305 mWindow.SetBackgroundColor(Color::WHITE);
306 mWindowSize = mWindow.GetSize();
308 mWindow.GetRootLayer().SetProperty(Layer::Property::DEPTH_TEST, false);
310 mSize = Vector3(mWindowSize.x / mColumnsCount, mWindowSize.y / mRowsCount, 0.0f);
312 Timer timer = Timer::New(mDurationPerColumns);
313 timer.TickSignal().Connect(this, &PerfViewCreation::OnTick);
314 mTimerList.push_back(timer);
316 mCreationStatistic.Clear();
324 // Respond to key events
325 mWindow.KeyEventSignal().Connect(this, &PerfViewCreation::OnKeyEvent);
331 if(mCreateCount < mColumnsCount)
334 Timer timer = Timer::New(mDurationPerColumns);
335 timer.TickSignal().Connect(this, &PerfViewCreation::OnTick);
336 mTimerList.push_back(timer);
342 void CreateColumnView()
347 GetNanoseconds(startTime);
348 DALI_TRACE_BEGIN(gTraceFilter, "DALI_SAMPLE_PERF_VIEW_CREATION");
350 Control columnView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS);
351 columnView.SetBackgroundColor(Color::BLUE);
352 columnView[Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_LEFT;
353 columnView[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_LEFT;
354 columnView[Actor::Property::SIZE] = Vector2(mSize.x, (float)mWindowSize.y);
355 columnView[Actor::Property::POSITION] = Vector2(mSize.x * (mCreateCount % mColumnsCount), -(float)mWindowSize.y);
356 for(uint32_t i = 0; i < mRowsCount; ++i)
361 case ControlTestType::COLOR:
364 bgView = CreateColor();
367 case ControlTestType::IMAGE:
369 bgView = CreateImage(mImageCount);
372 case ControlTestType::TEXT:
374 bgView = CreateTextLabel();
377 case ControlTestType::ROUNDED_COLOR:
379 bgView = CreateRoundedColor();
382 #if ALLOW_BORDER_AND_BLUR
383 case ControlTestType::BORDER_COLOR:
385 bgView = CreateBorderColor(std::min(mSize.x, mSize.y) * VIEW_MARGIN_RATE);
388 case ControlTestType::ROUNDED_BORDER_COLOR:
390 bgView = CreateRoundedBorderColor(std::min(mSize.x, mSize.y) * VIEW_MARGIN_RATE);
393 case ControlTestType::BLUR_COLOR:
395 bgView = CreateBlurColor(std::min(mSize.x, mSize.y) * VIEW_MARGIN_RATE * 0.5f);
398 case ControlTestType::ROUNDED_BLUR_COLOR:
400 bgView = CreateRoundedBlurColor(std::min(mSize.x, mSize.y) * VIEW_MARGIN_RATE * 0.5f);
406 bgView[Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_LEFT;
407 bgView[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_LEFT;
408 bgView[Actor::Property::SIZE] = Vector2(mSize.x * (1.0f - VIEW_MARGIN_RATE), mSize.y * (1.0f - VIEW_MARGIN_RATE));
409 bgView[Actor::Property::POSITION] = Vector2(mSize.x * VIEW_MARGIN_RATE * 0.5f, mSize.y * VIEW_MARGIN_RATE * 0.5f + mSize.y * i);
410 columnView.Add(bgView);
413 mWindow.GetRootLayer().Add(columnView);
414 mCreatingControlList.push_back(columnView);
416 // Add appearing animation
417 Animation appearingAnimation = Animation::New(mDurationOfAnimation * 0.001f);
418 appearingAnimation.AnimateTo(Property(columnView, Actor::Property::POSITION_Y), 0.0f);
419 appearingAnimation.FinishedSignal().Connect(this, &PerfViewCreation::OnAppearAnimationFinished);
420 appearingAnimation.Play();
422 mCreatingAnimationList.push_back(appearingAnimation);
424 GetNanoseconds(endTime);
426 DALI_TRACE_END(gTraceFilter, "DALI_SAMPLE_PERF_VIEW_CREATION");
428 // Append duration of creation time.
429 mCreationStatistic.Add((endTime - startTime) / 1000000.0);
433 if(mCreateCount % mTotalColumnsCount == 0)
435 DALI_LOG_ERROR("Average of creation %d DALI(%s) : %.6lf ms\n", mRowsCount, TestTypeString(mTestType), mCreationStatistic.GetTrimedAverage());
436 mCreationStatistic.Clear();
437 mTestType = static_cast<ControlTestType>((static_cast<int>(mTestType) + 1) % static_cast<int>(ControlTestType::TYPE_MAX));
441 bool OnTouch(Actor actor, const TouchEvent& touch)
443 // quit the application
448 void OnKeyEvent(const KeyEvent& event)
450 if(event.GetState() == KeyEvent::DOWN)
452 if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
459 void OnAppearAnimationFinished(Animation& animation)
461 // We can assume that front of mControlList must be disappearing.
462 auto currentControl = mCreatingControlList.front();
463 mCreatingControlList.pop_front();
465 // Dereference timer safety
466 if(mTimerList.empty())
468 mTimerList.pop_front();
471 // Dereference animation safety
472 mCreatingAnimationList.pop_back();
474 mRemovingControlList.push_back(currentControl);
476 if(mCreateCount < mTotalColumnsCount * (static_cast<int>(ControlTestType::TYPE_MAX)))
481 // Add disappearing animation
482 Animation disappearingAnimation = Animation::New(mDurationOfAnimation * 0.001f);
483 disappearingAnimation.AnimateTo(Property(currentControl, Actor::Property::POSITION_Y), (float)mWindowSize.y);
484 disappearingAnimation.FinishedSignal().Connect(this, &PerfViewCreation::OnDisappearAnimationFinished);
485 disappearingAnimation.Play();
487 mRemovingAnimationList.push_back(disappearingAnimation);
489 void OnDisappearAnimationFinished(Animation& animation)
491 // We can assume that front of mControlList must be deleted.
492 mRemovingControlList.front().Unparent();
493 mRemovingControlList.pop_front();
495 // Dereference animation safety
496 mRemovingAnimationList.pop_back();
500 // If all controls are deleted, quit this application. byebye~
501 if(mDeleteCount == mTotalColumnsCount * (static_cast<int>(ControlTestType::TYPE_MAX)))
503 GetNanoseconds(mAppEndTime);
505 DALI_LOG_ERROR("Duration of all app running time : %.6lf ms\n", (mAppEndTime - mAppStartTime) / 1000000.0);
511 Application& mApplication;
515 std::list<Control> mCreatingControlList;
516 std::list<Control> mRemovingControlList;
517 std::list<Animation> mCreatingAnimationList;
518 std::list<Animation> mRemovingAnimationList;
519 std::list<Timer> mTimerList;
523 const uint32_t mRowsCount;
524 const uint32_t mColumnsCount;
525 const uint32_t mTotalColumnsCount;
527 const uint32_t mDurationPerColumns;
528 const uint32_t mDurationOfAnimation;
530 ControlTestType mTestType;
532 uint32_t mCreateCount = 0;
533 uint32_t mDeleteCount = 0;
534 uint32_t mImageCount = 0;
536 uint64_t mAppStartTime = 0;
537 uint64_t mAppEndTime = 0;
539 Statistic<double> mCreationStatistic;
542 int DALI_EXPORT_API main(int argc, char** argv)
544 Application application = Application::New(&argc, &argv);
546 PerfViewCreation test(application);
547 application.MainLoop();