1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "display_manager.h"
17 #include "rs_graphic_test_director.h"
18 #include "rs_graphic_test_utils.h"
19 #include "rs_trace.h"
20 #include "rs_parameter_parse.h"
21 #include "transaction/rs_interfaces.h"
22 #include "ui/rs_root_node.h"
23 #include "ui/rs_surface_node.h"
24 #include "ui/rs_ui_director.h"
25
26 #include <chrono>
27 #include <condition_variable>
28 #include <mutex>
29 #include <filesystem>
30
31 namespace OHOS {
32 namespace Rosen {
33 namespace {
34 constexpr float TOP_LEVEL_Z = 1000000.0f;
35 constexpr uint32_t SCREEN_COLOR = 0;
36 constexpr int64_t WAIT_ANIMATION_SYNC_TIME_OUT = 100;
37
38 class TestSurfaceCaptureCallback : public SurfaceCaptureCallback {
39 public:
OnSurfaceCapture(std::shared_ptr<Media::PixelMap> pixelMap)40 void OnSurfaceCapture(std::shared_ptr<Media::PixelMap> pixelMap) override
41 {
42 {
43 std::unique_lock lock(mutex_);
44 ready_ = true;
45 pixelMap_ = pixelMap;
46 }
47 cv_.notify_all();
48
49 if (pixelMap == nullptr) {
50 LOGE("RSGraphicTestDirector pixelMap == nullptr");
51 }
52 }
53
Wait(int ms)54 void Wait(int ms)
55 {
56 std::unique_lock lock(mutex_);
57 cv_.wait_for(lock, std::chrono::milliseconds(ms), [&] { return ready_; });
58 }
59
60 std::mutex mutex_;
61 std::condition_variable cv_;
62 bool ready_ = false;
63 std::shared_ptr<Media::PixelMap> pixelMap_;
64 };
65 }
66
67 class VSyncWaiter {
68 public:
VSyncWaiter(std::shared_ptr<OHOS::AppExecFwk::EventHandler> handler)69 explicit VSyncWaiter(std::shared_ptr<OHOS::AppExecFwk::EventHandler> handler)
70 {
71 frameCallback_ = {
72 .userData_ = this,
73 .callback_ = [this](int64_t timestamp, void*) { this->OnVSync(timestamp); },
74 };
75 vsyncReceiver_ = RSInterfaces::GetInstance().CreateVSyncReceiver("RSGraphicTest", handler);
76 vsyncReceiver_->Init();
77 }
78
OnVSync(int64_t timestamp)79 void OnVSync(int64_t timestamp)
80 {
81 {
82 std::unique_lock lock(mutex_);
83 ready_ = true;
84 time_ = time_ + ANIMATION_VSYNC_TIME_MS * UNIT_MS_TO_NS;
85 }
86 RS_TRACE_NAME_FMT("VSyncWaiter Send OnVSync time is %llu", time_);
87 cv_.notify_all();
88 }
89
RequestNextVSync()90 void RequestNextVSync()
91 {
92 if (vsyncReceiver_) {
93 vsyncReceiver_->RequestNextVSync(frameCallback_);
94 }
95 {
96 std::unique_lock lock(mutex_);
97 ready_ = false;
98 cv_.wait_for(lock, std::chrono::milliseconds(WAIT_ANIMATION_SYNC_TIME_OUT), [&] { return ready_; });
99 }
100 RSGraphicTestDirector::Instance().OnVSync(time_);
101 }
102
InitStartTime()103 void InitStartTime()
104 {
105 struct timespec ts;
106 clock_gettime(CLOCK_MONOTONIC, &ts);
107 time_ = ts.tv_sec * SEC_TO_NANOSEC + ts.tv_nsec;
108 }
109
110 private:
111 std::mutex mutex_;
112 std::condition_variable cv_;
113 bool ready_ = false;
114 int64_t time_;
115 std::shared_ptr<OHOS::Rosen::VSyncReceiver> vsyncReceiver_;
116 Rosen::VSyncReceiver::FrameCallback frameCallback_;
117 };
118
Instance()119 RSGraphicTestDirector& RSGraphicTestDirector::Instance()
120 {
121 static RSGraphicTestDirector instance;
122 return instance;
123 }
124
~RSGraphicTestDirector()125 RSGraphicTestDirector::~RSGraphicTestDirector()
126 {
127 rootNode_->screenSurfaceNode_->RemoveFromTree();
128 rsUiDirector_->SendMessages();
129 runner_->Stop();
130 sleep(1);
131 }
132
Run()133 void RSGraphicTestDirector::Run()
134 {
135 rsUiDirector_ = RSUIDirector::Create();
136 rsUiDirector_->Init();
137
138 rsUiDirector_->SetUITaskRunner([](const std::function<void()>& task, uint32_t delay) {
139 if (task) {
140 task();
141 }
142 });
143
144 runner_ = OHOS::AppExecFwk::EventRunner::Create(true);
145 handler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner_);
146 vsyncWaiter_ = std::make_shared<VSyncWaiter>(handler_);
147 runner_->Run();
148
149 screenId_ = RSInterfaces::GetInstance().GetDefaultScreenId();
150
151 auto defaultDisplay = DisplayManager::GetInstance().GetDefaultDisplay();
152 Vector4f defaultScreenBounds = {0, 0, defaultDisplay->GetWidth(), defaultDisplay->GetHeight()};
153 screenBounds_ = defaultScreenBounds;
154
155 rootNode_ = std::make_shared<RSGraphicRootNode>();
156 rootNode_->screenSurfaceNode_->SetBounds(defaultScreenBounds);
157 rootNode_->screenSurfaceNode_->SetFrame(defaultScreenBounds);
158 rootNode_->screenSurfaceNode_->SetBackgroundColor(SCREEN_COLOR);
159 rootNode_->screenSurfaceNode_->AttachToDisplay(screenId_);
160 rootNode_->screenSurfaceNode_->SetPositionZ(TOP_LEVEL_Z);
161
162 rsUiDirector_->SetRSSurfaceNode(rootNode_->screenSurfaceNode_);
163 rsUiDirector_->SendMessages();
164 sleep(1);
165
166 ResetImagePath();
167 }
168
FlushMessage()169 void RSGraphicTestDirector::FlushMessage()
170 {
171 RS_TRACE_NAME("RSGraphicTestDirector::FlushMessage");
172 rsUiDirector_->SendMessages();
173 }
174
TakeScreenCaptureAndWait(int ms)175 std::shared_ptr<Media::PixelMap> RSGraphicTestDirector::TakeScreenCaptureAndWait(int ms)
176 {
177 RS_TRACE_NAME("RSGraphicTestDirector::TakeScreenCaptureAndWait");
178 auto callback = std::make_shared<TestSurfaceCaptureCallback>();
179 if (!RSInterfaces::GetInstance().TakeSurfaceCaptureForUI(rootNode_->screenSurfaceNode_, callback)) {
180 return nullptr;
181 }
182
183 callback->Wait(ms);
184 return callback->pixelMap_;
185 }
186
ResetImagePath()187 void RSGraphicTestDirector::ResetImagePath()
188 {
189 namespace fs = std::filesystem;
190 const auto& path = RSParameterParse::Instance().imageSavePath;
191 if (!fs::exists(path)) {
192 if (!fs::create_directories(path)) {
193 LOGE("RSGraphicTestDirector create dir failed %{public}s", path.c_str());
194 }
195 } else {
196 if (!fs::is_directory(path) || !fs::is_empty(path)) {
197 LOGE("RSGraphicTestDirector path is not dir or not empty %{public}s", path.c_str());
198 }
199 }
200 }
201
GetRootNode() const202 std::shared_ptr<RSGraphicRootNode> RSGraphicTestDirector::GetRootNode() const
203 {
204 return rootNode_;
205 }
206
GetScreenSize() const207 Vector2f RSGraphicTestDirector::GetScreenSize() const
208 {
209 return {screenBounds_.GetWidth(), screenBounds_.GetHeight()};
210 }
211
SetScreenSize(float width,float height)212 void RSGraphicTestDirector::SetScreenSize(float width, float height)
213 {
214 screenBounds_ = {0, 0, width, height};
215 }
216
SetSingleTest(bool isSingleTest)217 void RSGraphicTestDirector::SetSingleTest(bool isSingleTest)
218 {
219 isSingleTest_ = isSingleTest;
220 }
221
IsSingleTest()222 bool RSGraphicTestDirector::IsSingleTest()
223 {
224 return isSingleTest_;
225 }
226
SetSurfaceBounds(const Vector4f & bounds)227 void RSGraphicTestDirector::SetSurfaceBounds(const Vector4f& bounds)
228 {
229 if (rootNode_->testSurfaceNode_) {
230 rootNode_->testSurfaceNode_->SetBounds(bounds);
231 }
232 }
233
SetScreenSurfaceBounds(const Vector4f & bounds)234 void RSGraphicTestDirector::SetScreenSurfaceBounds(const Vector4f& bounds)
235 {
236 if (rootNode_->screenSurfaceNode_) {
237 rootNode_->screenSurfaceNode_->SetBounds(bounds);
238 rootNode_->screenSurfaceNode_->SetFrame(bounds);
239 }
240 }
241
SetSurfaceColor(const RSColor & color)242 void RSGraphicTestDirector::SetSurfaceColor(const RSColor& color)
243 {
244 if (rootNode_->testSurfaceNode_) {
245 rootNode_->testSurfaceNode_->SetBackgroundColor(color.AsRgbaInt());
246 }
247 }
248
StartRunUIAnimation()249 void RSGraphicTestDirector::StartRunUIAnimation()
250 {
251 if (HasUIRunningAnimation()) {
252 if (vsyncWaiter_) {
253 vsyncWaiter_->InitStartTime();
254 }
255 // request first frame
256 RequestNextVSync();
257 }
258 }
259
HasUIRunningAnimation()260 bool RSGraphicTestDirector::HasUIRunningAnimation()
261 {
262 return rsUiDirector_->HasUIRunningAnimation();
263 }
264
FlushAnimation(int64_t time)265 void RSGraphicTestDirector::FlushAnimation(int64_t time)
266 {
267 RS_TRACE_NAME_FMT("RSGraphicTestDirector FlushAnimation time is %llu", time);
268 rsUiDirector_->FlushAnimation(time);
269 rsUiDirector_->FlushModifier();
270 }
271
RequestNextVSync()272 void RSGraphicTestDirector::RequestNextVSync()
273 {
274 if (vsyncWaiter_) {
275 vsyncWaiter_->RequestNextVSync();
276 }
277 }
278
OnVSync(int64_t time)279 void RSGraphicTestDirector::OnVSync(int64_t time)
280 {
281 FlushAnimation(time);
282 //also have animation request next frame
283 if (HasUIRunningAnimation()) {
284 RequestNextVSync();
285 }
286 }
287 } // namespace Rosen
288 } // namespace OHOS
289