* Copyright (c) 2020-2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "core/render_manager.h"
#include "components/root_view.h"
#include "gfx_utils/graphic_log.h"
#include "hal_tick.h"
#include "securec.h"
#if ENABLE_WINDOW
#include "window/window_impl.h"
#endif
namespace OHOS {
RenderManager::RenderManager() : fps_(0.f), needResetFPS_(true), onFPSChangedListener_(nullptr) {}
RenderManager::~RenderManager() {}
RenderManager& RenderManager::GetInstance()
{
static RenderManager instance;
return instance;
}
void RenderManager::Init()
{
Task::Init();
}
void RenderManager::Callback()
{
#if ENABLE_WINDOW
ListNode<Window*>* winNode = winList_.Begin();
while (winNode != winList_.End()) {
WindowImpl* windowImpl = reinterpret_cast<WindowImpl*>(winNode->data_);
windowImpl->Render();
winNode = winNode->next_;
}
#else
RootView* rootView = RootView::GetInstance();
rootView->Measure();
rootView->Render();
#endif
#if ENABLE_FPS_SUPPORT
UpdateFPS();
#endif
}
#if ENABLE_FPS_SUPPORT
void RenderManager::UpdateFPS()
{
SysInfo::FPSCalculateType type = SysInfo::FPS_CT_FIXED_TIME;
if (onFPSChangedListener_) {
type = onFPSChangedListener_->GetFPSCalculateType();
}
if (type == SysInfo::FPS_CT_FIXED_TIME) {
UpdateFPSByFixedTimeMethod();
} else if (type == SysInfo::FPS_CT_AVERAGE_SAMPLING) {
UpdateFPSByAverageSamplingMethod();
} else if (type == SysInfo::FPS_CT_PRECISE_SAMPLING) {
UpdateFPSByPreciseSamplingMethod();
}
OnFPSChanged(fps_);
}
void RenderManager::UpdateFPSByFixedTimeMethod()
{
static uint16_t frameCount = 0;
static uint32_t lastTime = HALTick::GetInstance().GetTime();
if (needResetFPS_) {
frameCount = 0;
lastTime = HALTick::GetInstance().GetTime();
needResetFPS_ = false;
fps_ = 0.f;
return;
}
frameCount++;
uint32_t curTime = HALTick::GetInstance().GetTime();
if (curTime - lastTime > MILLISECONDS_PER_SECOND) {
fps_ = 1.f * frameCount / (curTime - lastTime) * MILLISECONDS_PER_SECOND;
fps_ = (fps_ > MAX_FPS) ? MAX_FPS : fps_;
frameCount = 0;
lastTime = curTime;
}
}
void RenderManager::UpdateFPSByAverageSamplingMethod()
{
static float avgDuration = 0.f;
static float alpha = 1.f / SAMPLE_NUMBER;
static bool firstFrame = true;
static uint32_t lastTime = HALTick::GetInstance().GetTime();
if (needResetFPS_) {
avgDuration = 0.f;
alpha = 1.f / SAMPLE_NUMBER;
firstFrame = true;
lastTime = HALTick::GetInstance().GetTime();
needResetFPS_ = false;
fps_ = 0.f;
return;
}
uint32_t curTime = HALTick::GetInstance().GetTime();
int32_t deltaTime = curTime - lastTime;
lastTime = curTime;
if (firstFrame) {
avgDuration = static_cast<float>(deltaTime);
firstFrame = false;
} else {
avgDuration = avgDuration * (1 - alpha) + deltaTime * alpha;
}
fps_ = 1.f / avgDuration * MILLISECONDS_PER_SECOND;
}
void RenderManager::UpdateFPSByPreciseSamplingMethod()
{
static int32_t deltaTimeQueue[SAMPLE_NUMBER] = {0};
static int32_t frameCount = 0;
static int32_t sumDuration = 0;
static bool isQueueFull = false;
static uint32_t lastTime = HALTick::GetInstance().GetTime();
if (needResetFPS_) {
if (memset_s(deltaTimeQueue, sizeof(deltaTimeQueue), 0, sizeof(deltaTimeQueue)) != EOK) {
return;
}
frameCount = 0;
sumDuration = 0;
isQueueFull = false;
lastTime = HALTick::GetInstance().GetTime();
needResetFPS_ = false;
fps_ = 0.f;
return;
}
uint32_t curTime = HALTick::GetInstance().GetTime();
int32_t deltaTime = curTime - lastTime;
lastTime = curTime;
if (!isQueueFull && (frameCount == SAMPLE_NUMBER)) {
isQueueFull = true;
}
frameCount %= SAMPLE_NUMBER;
sumDuration -= deltaTimeQueue[frameCount];
sumDuration += deltaTime;
deltaTimeQueue[frameCount++] = deltaTime;
if (isQueueFull) {
fps_ = 1.f * SAMPLE_NUMBER / sumDuration * MILLISECONDS_PER_SECOND;
} else {
fps_ = 1.f * frameCount / sumDuration * MILLISECONDS_PER_SECOND;
}
}
#endif
void RenderManager::RenderRect(const Rect& rect, RootView* rootView)
{
if (rootView == nullptr) {
return;
}
Rect mask = rect;
#if ENABLE_WINDOW
if (rootView->GetBoundWindow()) {
Rect winRect = rootView->GetBoundWindow()->GetRect();
winRect.SetPosition(0, 0);
mask.Intersect(rect, winRect);
}
#endif
#if LOCAL_RENDER
rootView->DrawInvalidMap(mask);
#else
UIView* topView = rootView->GetTopUIView(mask);
rootView->DrawTop(topView, mask);
#endif
}
void RenderManager::RefreshScreen()
{
#if ENABLE_WINDOW
ListNode<Window*>* winNode = winList_.Begin();
while (winNode != winList_.End()) {
WindowImpl* windowImpl = reinterpret_cast<WindowImpl*>(winNode->data_);
RootView* rootView = windowImpl->GetRootView();
if (rootView == nullptr) {
winNode = winNode->next_;
continue;
}
rootView->Invalidate();
winNode = winNode->next_;
}
#else
RootView::GetInstance()->Invalidate();
#endif
}
#if ENABLE_WINDOW
void RenderManager::AddToDisplay(Window* window)
{
if (window == nullptr) {
return;
}
winList_.PushBack(window);
}
void RenderManager::RemoveFromDisplay(Window* window)
{
if (window == nullptr) {
return;
}
ListNode<Window*>* winNode = winList_.Begin();
while (winNode != winList_.End()) {
if (winNode->data_ == window) {
winList_.Remove(winNode);
return;
}
winNode = winNode->next_;
}
}
#endif
}