1 /*
2  * Copyright (c) 2021-2022 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 <iostream>
17 #include <surface.h>
18 
19 #include "command/rs_base_node_command.h"
20 #include "command/rs_display_node_command.h"
21 #include "command/rs_surface_node_command.h"
22 #include "common/rs_common_def.h"
23 #include "pipeline/rs_render_result.h"
24 #include "pipeline/rs_render_thread.h"
25 #include "ui/rs_canvas_node.h"
26 #include "ui/rs_surface_extractor.h"
27 #include "ui/rs_ui_director.h"
28 #include "transaction/rs_interfaces.h"
29 #include "ui/rs_display_node.h"
30 #include "ui/rs_surface_node.h"
31 #include "render_context/render_context.h"
32 // temporary debug
33 #include "foundation/graphic/graphic_2d/rosen/modules/render_service_base/src/platform/ohos/rs_surface_frame_ohos.h"
34 #include "foundation/graphic/graphic_2d/rosen/modules/render_service_base/src/platform/ohos/rs_surface_ohos.h"
35 
36 using namespace OHOS;
37 using namespace OHOS::Rosen;
38 using namespace std;
39 
40 namespace OHOS::Rosen {
41 namespace {
42 constexpr int SURFACE_NODE_SIZE = 100;
43 constexpr int SLEEP_TIME = 8;
44 }
45 #ifdef RS_ENABLE_GPU
46     RenderContext* rc_ = nullptr;
47 #endif
48 
49 namespace pipelineTestUtils {
50     constexpr bool wrongExit = false;
51     constexpr bool successExit = false;
52     struct Circle {
CircleOHOS::Rosen::pipelineTestUtils::Circle53         Circle(float x, float y, float r)
54             :x_(x), y_(y), r_(r) {};
55         float x_ = 0.0f;
56         float y_ = 0.0f;
57         float r_ = 0.0f;
58     }; // class Circle
59 
60     class ToDrawSurface {
61     public:
62         using drawFun = std::function<void(Drawing::Canvas&, Drawing::Brush&)>;
ToDrawSurface()63         ToDrawSurface() {};
64 
SetSurfaceNode(const std::shared_ptr<RSSurfaceNode> surfaceNode)65         inline ToDrawSurface& SetSurfaceNode(const std::shared_ptr<RSSurfaceNode> surfaceNode)
66         {
67             surfaceNode_ = surfaceNode;
68             return *this;
69         }
70 
SetSurfaceNodeSize(Drawing::Rect surfaceGeometry)71         inline ToDrawSurface& SetSurfaceNodeSize(Drawing::Rect surfaceGeometry)
72         {
73             surfaceGeometry_ = surfaceGeometry;
74             return *this;
75         }
76 
SetBufferSize(int width,int height)77         inline ToDrawSurface& SetBufferSize(int width, int height)
78         {
79             bufferSize_ = Drawing::Rect(0, 0, width, height);
80             return *this;
81         }
82 
SetBufferSizeAuto()83         inline ToDrawSurface& SetBufferSizeAuto()
84         {
85             bufferSize_ = surfaceGeometry_;
86             return *this;
87         }
88 
SetBufferSize(Drawing::Rect bufferSize)89         inline ToDrawSurface& SetBufferSize(Drawing::Rect bufferSize)
90         {
91             // bufferSize has no XY
92             bufferSize_ = bufferSize;
93             return *this;
94         }
95 
SetShapeColor(uint32_t color)96         inline ToDrawSurface& SetShapeColor(uint32_t color)
97         {
98             color_ = color;
99             return *this;
100         }
101 
SetDraw(drawFun drawShape)102         inline ToDrawSurface& SetDraw(drawFun drawShape)
103         {
104             drawShape_ = drawShape;
105             return *this;
106         }
107 
Run()108         bool Run()
109         {
110             printf("ToDrawSurface::Run() start\n");
111             if (surfaceNode_ == nullptr) {
112                 printf("DrawSurface: surfaceNode_ is nullptr\n");
113                 return false;
114             }
115             auto x = surfaceGeometry_.GetLeft();
116             auto y = surfaceGeometry_.GetTop();
117             auto width = surfaceGeometry_.GetWidth();
118             auto height = surfaceGeometry_.GetHeight();
119             surfaceNode_->SetBounds(x, y, width, height);
120             std::shared_ptr<RSSurface> rsSurface = RSSurfaceExtractor::ExtractRSSurface(surfaceNode_);
121             if (rsSurface == nullptr) {
122                 return wrongExit;
123             }
124 #ifdef RS_ENABLE_GPU
125             // SetRenderContext must before rsSurface->RequestFrame, or it will failed.
126             if (rc_) {
127                 rsSurface->SetRenderContext(rc_);
128             } else {
129                 printf("DrawSurface: RenderContext is nullptr\n");
130             }
131 #endif
132             auto framePtr = rsSurface->RequestFrame(bufferSize_.GetWidth(), bufferSize_.GetHeight());
133             if (!framePtr) {
134                 // SetRenderContext must before rsSurface->RequestFrame,
135                 //      or frameptr will be nullptr.
136                 printf("DrawSurface: frameptr is nullptr\n");
137                 return wrongExit;
138             }
139             auto canvas = framePtr->GetCanvas();
140             if (!canvas) {
141                 printf("DrawSurface: canvas is nullptr\n");
142                 return wrongExit;
143             }
144             canvas->Clear(Drawing::Color::COLOR_TRANSPARENT);
145             Drawing::Brush brush;
146             brush.SetAntiAlias(true);
147             brush.SetColor(color_);
148             if (!drawShape_) {
149                 printf("DrawSurface: drawShape_ is nullptr\n");
150                 return wrongExit;
151             }
152             drawShape_(*canvas, brush);
153             framePtr->SetDamageRegion(0, 0, surfaceGeometry_.GetWidth(), surfaceGeometry_.GetHeight());
154             rsSurface->FlushFrame(framePtr);
155             return successExit;
156         }
157     private:
158         Drawing::Rect surfaceGeometry_ = {0.f, 0.f, 0.f, 0.f};
159         Drawing::Rect bufferSize_ = {0.f, 0.f, 0.f, 0.f};
160         drawFun drawShape_;
161         uint32_t color_ = 0;
162         std::shared_ptr<RSSurfaceNode> surfaceNode_ = nullptr;
163     }; // class ToDrawSurface
164 
CreateSurface()165     static std::shared_ptr<RSSurfaceNode> CreateSurface()
166     {
167         RSSurfaceNodeConfig config;
168         return RSSurfaceNode::Create(config);
169     }
170 } // namespace pipelineTestUtils
171 
172 // Toy DMS.
173 using DisplayId = ScreenId;
174 class DmsMock {
175 private:
176     struct Display {
177         DisplayId id;
178         RSScreenModeInfo activeMode;
179     };
180     std::unordered_map<DisplayId, Display> displays_;
181     mutable std::recursive_mutex mutex_;
182     RSInterfaces& rsInterface_;
183     DisplayId defaultDisplayId_;
184 
DmsMock()185     DmsMock() : rsInterface_(RSInterfaces::GetInstance())
186     {
187         Init();
188     }
189 
Init()190     void Init()
191     {
192         std::lock_guard<std::recursive_mutex> lock(mutex_);
193         (void)rsInterface_.SetScreenChangeCallback([this](ScreenId id, ScreenEvent event) {
194             switch (event) {
195                 case ScreenEvent::CONNECTED: {
196                     this->OnDisplayConnected(id);
197                     break;
198                 }
199                 case ScreenEvent::DISCONNECTED: {
200                     this->OnDisplayDisConnected(id);
201                     break;
202                 }
203                 default:
204                     break;
205             }
206         });
207 
208         defaultDisplayId_ = rsInterface_.GetDefaultScreenId();
209         displays_[defaultDisplayId_] =
210             Display { defaultDisplayId_, rsInterface_.GetScreenActiveMode(defaultDisplayId_) };
211     }
212 
213 public:
GetInstance()214     inline static DmsMock& GetInstance()
215     {
216         static DmsMock c;
217         return c;
218     }
219 
220     ~DmsMock() noexcept = default;
221 
GetDefaultDisplayId() const222     DisplayId GetDefaultDisplayId() const
223     {
224         std::lock_guard<std::recursive_mutex> lock(mutex_);
225         return defaultDisplayId_;
226     }
227 
GetDisplayActiveMode(DisplayId id) const228     std::optional<RSScreenModeInfo> GetDisplayActiveMode(DisplayId id) const
229     {
230         std::lock_guard<std::recursive_mutex> lock(mutex_);
231         if (displays_.count(id) == 0) {
232             cout << "DmsMock: No display " << id << "!" << endl;
233             return {};
234         }
235         return displays_.at(id).activeMode;
236     }
237 
OnDisplayConnected(ScreenId id)238     void OnDisplayConnected(ScreenId id)
239     {
240         std::lock_guard<std::recursive_mutex> lock(mutex_);
241         displays_[id] = Display { id, rsInterface_.GetScreenActiveMode(id) };
242         std::cout << "DmsMock: Display " << id << " connected." << endl;
243     }
244 
OnDisplayDisConnected(ScreenId id)245     void OnDisplayDisConnected(ScreenId id)
246     {
247         std::lock_guard<std::recursive_mutex> lock(mutex_);
248         if (displays_.count(id) == 0) {
249             cout << "DmsMock: No display " << id << "!" << endl;
250         } else {
251             std::cout << "DmsMock: Display " << id << " disconnected." << endl;
252             displays_.erase(id);
253             if (id == defaultDisplayId_) {
254                 defaultDisplayId_ = rsInterface_.GetDefaultScreenId();
255                 std::cout << "DmsMock: DefaultDisplayId changed, new DefaultDisplayId is" << defaultDisplayId_ << "."
256                           << endl;
257             }
258         }
259     }
260 }; // class DmsMock
261 
262 class RSDemoTestCase {
263 public:
GetInstance()264     inline static RSDemoTestCase& GetInstance()
265     {
266         static RSDemoTestCase c;
267         return c;
268     }
269 
TestInit()270     void TestInit()
271     {
272         isInit_ = true;
273         std::cout << "Render service Client rs Demo.cpp testInit Start\n";
274 
275 #ifdef RS_ENABLE_GPU
276         std::cout << "RS_ENABLE_GPU is enabled\n";
277         isGPU_ = true;
278 #else
279         std::cout << "RS_ENABLE_GPU is disabled\n";
280         isGPU_ = false;
281 #endif
282 
283         DisplayId id = DmsMock::GetInstance().GetDefaultDisplayId();
284         std::cout << "RS default screen id is " << id << ".\n";
285         auto activeModeInfo = DmsMock::GetInstance().GetDisplayActiveMode(id);
286         if (activeModeInfo) {
287             screenWidth_ = activeModeInfo->GetScreenWidth();
288             screenheight_ = activeModeInfo->GetScreenHeight();
289             screenRefreshRate_ = static_cast<int>(activeModeInfo->GetScreenRefreshRate());
290             std::cout << "Display " << id << " active mode info:\n";
291             std::cout << "Width: " << screenWidth_ << ", Height: " << screenheight_;
292             std::cout << ", RefreshRate: " << screenRefreshRate_ << "Hz.\n";
293         } else {
294             std::cout << "Display " << id << " has no active mode!\n";
295         }
296         RenderContextInit();
297         std::cout << "Render service Client rs Demo.cpp testInit end\n";
298         std::cout << "-------------------------------------------------------\n";
299         return;
300     }
301 
TestCaseDefault()302     void TestCaseDefault()
303     {
304         std::cout << "-------------------------------------------------------\n";
305         std::cout << "Render service Client rs Demo.cpp testCaseDefault Start\n";
306         auto surfaceNode1 = pipelineTestUtils::CreateSurface();
307         auto surfaceNode2 = pipelineTestUtils::CreateSurface();
308 
309         pipelineTestUtils::ToDrawSurface()
310             .SetSurfaceNode(surfaceNode1)
311             .SetShapeColor(0xff00ffff)
312             .SetSurfaceNodeSize(Drawing::Rect(SURFACE_NODE_SIZE, 0,
313                 screenWidth_ * 0.4f + SURFACE_NODE_SIZE, screenheight_ * 0.3f))
314             .SetBufferSizeAuto()
315             .SetDraw([&](Drawing::Canvas &canvas, Drawing::Brush &brush) -> void {
316                 canvas.AttachBrush(brush);
317                 canvas.DrawRect(Drawing::Rect(0, 0, screenWidth_ * 0.4f, screenheight_ * 0.3f));
318                 canvas.DetachBrush();
319             })
320             .Run();
321 
322         pipelineTestUtils::ToDrawSurface()
323             .SetSurfaceNode(surfaceNode2)
324             .SetShapeColor(0xffff0000)
325             .SetSurfaceNodeSize(Drawing::Rect(SURFACE_NODE_SIZE, screenheight_ * 0.8f,
326                 screenWidth_ * 0.4f + SURFACE_NODE_SIZE, screenheight_))
327             .SetBufferSizeAuto()
328             .SetDraw([&](Drawing::Canvas &canvas, Drawing::Brush &brush) -> void {
329                 canvas.AttachBrush(brush);
330                 canvas.DrawRect(Drawing::Rect(0, 0, screenWidth_ * 0.4f, screenheight_ * 0.2f));
331                 canvas.DetachBrush();
332             })
333             .Run();
334 
335         RSDisplayNodeConfig config;
336         RSDisplayNode::SharedPtr displayNode = RSDisplayNode::Create(config);
337         displayNode->AddChild(surfaceNode1, -1);
338         displayNode->AddChild(surfaceNode2, -1);
339 
340         auto transactionProxy = RSTransactionProxy::GetInstance();
341         if (transactionProxy != nullptr) {
342             transactionProxy->FlushImplicitTransaction();
343         }
344         sleep(SLEEP_TIME);
345         displayNode->RemoveFromTree();
346         if (transactionProxy != nullptr) {
347             transactionProxy->FlushImplicitTransaction();
348         }
349         std::cout << "Render service Client rs Demo.cpp testCaseDefault end\n";
350         std::cout << "-------------------------------------------------------\n";
351     }
352 private:
353     RSDemoTestCase() = default;
RenderContextInit()354     static void RenderContextInit()
355     {
356 #ifdef RS_ENABLE_GPU
357         std::cout << "RS_ENABLE_GPU is true. \n";
358         std::cout << "Init RenderContext start. \n";
359             rc_ = RenderContextFactory::GetInstance().CreateEngine();
360             if (rc_) {
361                 std::cout << "Init RenderContext success.\n";
362                 rc_->InitializeEglContext();
363             } else {
364                 std::cout << "Init RenderContext failed, RenderContext is nullptr.\n";
365             }
366         std::cout << "Init RenderContext start.\n";
367 #endif
368     }
369 
370     bool isInit_ = false;
371     bool isGPU_ = false;
372     int screenWidth_ = 0;
373     int screenheight_ = 0;
374     int screenRefreshRate_ = 0;
375 }; // class RSDemoTestCase
376 } // namespace OHOS::Rosen
377 
main()378 int main()
379 {
380     RSDemoTestCase::GetInstance().TestInit();
381     RSDemoTestCase::GetInstance().TestCaseDefault();
382     return 0;
383 }
384