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 <filesystem>
17 namespace fs = std::filesystem;
18 #include <iostream>
19 #include <string>
20
21 #include <sys/mman.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <unique_fd.h>
26 #include "directory_ex.h"
27
28 #include "window.h"
29
30 #include "drawing_sample_replayer.h"
31
32 namespace OHOS::Rosen {
33
~DrawingSampleReplayer()34 DrawingSampleReplayer::~DrawingSampleReplayer()
35 {
36 DestoryNativeWindow(nativeWindow_);
37 if (surfaceNode_) {
38 surfaceNode_->DetachToDisplay(defaultDisplayId_);
39 }
40 }
41
ReadCmds(const std::string path)42 bool DrawingSampleReplayer::ReadCmds(const std::string path)
43 {
44 std::string realPath;
45 if (!PathToRealPath(path, realPath)) {
46 std::cout << "PathToRealPath fails on: " << path;
47 return false;
48 }
49 UniqueFd fd(open(realPath.c_str(), O_RDONLY));
50 if (fd <= 0) {
51 return false;
52 }
53 struct stat statbuf;
54 if (fstat(fd.Get(), &statbuf) < 0) {
55 return false;
56 }
57 auto mapFile = static_cast<uint8_t*>(mmap(nullptr, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0));
58 if (mapFile == MAP_FAILED) {
59 return false;
60 }
61 MessageParcel messageParcel(new EmptyAllocator());
62 if (!messageParcel.ParseFrom(reinterpret_cast<uintptr_t>(mapFile), statbuf.st_size)) {
63 munmap(mapFile, statbuf.st_size);
64 return false;
65 }
66 RSMarshallingHelper::BeginNoSharedMem(std::this_thread::get_id());
67 RSMarshallingHelper::Unmarshalling(messageParcel, dcl_);
68 RSMarshallingHelper::EndNoSharedMem();
69 if (dcl_ == nullptr) {
70 std::cout << "dcl is nullptr" << std::endl;
71 munmap(mapFile, statbuf.st_size);
72 return false;
73 }
74 munmap(mapFile, statbuf.st_size);
75 return true;
76 }
77
InitCapturingSKP(Drawing::Canvas * canvas)78 bool DrawingSampleReplayer::InitCapturingSKP(Drawing::Canvas* canvas)
79 {
80 #if (defined RS_ENABLE_GL) || (defined RS_ENABLE_VK)
81 if (captureMode_ == CaptureMode::SKP) {
82 orgSkiaCanvas_ = canvas->GetImpl<Drawing::SkiaCanvas>()->ExportSkCanvas();
83 recorder_ = std::make_unique<SkPictureRecorder>();
84 pictureCanvas_ = recorder_->beginRecording(width_, height_);
85 if (pictureCanvas_ == nullptr) {
86 return false;
87 }
88 if (nwayCanvas_ == nullptr) {
89 nwayCanvas_ = std::make_unique<SkNWayCanvas>(width_, height_);
90 }
91 nwayCanvas_->addCanvas(orgSkiaCanvas_);
92 nwayCanvas_->addCanvas(pictureCanvas_);
93
94 canvas->GetImpl<Drawing::SkiaCanvas>()->ImportSkCanvas(nwayCanvas_.get());
95 return true;
96 }
97 #endif
98 return false;
99 }
100
FinilizeCapturingSKP(Drawing::Canvas * canvas)101 void DrawingSampleReplayer::FinilizeCapturingSKP(Drawing::Canvas* canvas)
102 {
103 #if (defined RS_ENABLE_GL) || (defined RS_ENABLE_VK)
104 if (captureMode_ == CaptureMode::SKP) {
105 // finishing capturing and saving skp
106 nwayCanvas_->removeAll();
107 sk_sp<SkPicture> picture = recorder_->finishRecordingAsPicture();
108 if (picture->approximateOpCount() > 0) {
109 SkSerialProcs procs;
110 procs.fTypefaceProc = [](SkTypeface* tf, void* ctx) {
111 return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
112 };
113 auto data = picture->serialize(&procs);
114 // to save locally
115 std::string outputFile = "/data/default.skp";
116 SkFILEWStream stream(outputFile.c_str());
117 if (stream.isValid()) {
118 stream.write(data->data(), data->size());
119 stream.flush();
120 std::cout << "Written and flushed" << std::endl;
121 } else {
122 std::cout << "Failed to create stream" << std::endl;
123 }
124 }
125 canvas->GetImpl<Drawing::SkiaCanvas>()->ImportSkCanvas(orgSkiaCanvas_);
126 }
127 #endif
128 }
129
PrepareFrame(Drawing::Canvas * canvas)130 bool DrawingSampleReplayer::PrepareFrame(Drawing::Canvas* canvas)
131 {
132 if (canvas == nullptr) {
133 return false;
134 }
135 bool captureStarted = InitCapturingSKP(canvas);
136 // for now we capture single frame only
137 if (!ReadCmds("/data/default.drawing")) {
138 std::cout << "Failed to load .drawing cmds" << std::endl;
139 return false;
140 }
141 dcl_->Playback(*canvas);
142 if (captureStarted) {
143 FinilizeCapturingSKP(canvas);
144 }
145 return true;
146 }
147
RenderLoop()148 bool DrawingSampleReplayer::RenderLoop()
149 {
150 PrepareNativeEGLSetup();
151 int maxIter = (captureMode_ == CaptureMode::RDC) ? maxRenderedFrames_ : 1;
152
153 for (int i = 0; i < maxIter; ++i) {
154 std::shared_ptr<Drawing::Surface> drawingSurface = renderContext_->AcquireSurface(width_, height_);
155 Drawing::Canvas* canvas = drawingSurface->GetCanvas().get();
156
157 std::cout << i << "\t >> new iteration" << std::endl;
158
159 if (!PrepareFrame(canvas)) {
160 return false;
161 }
162
163 renderContext_->RenderFrame(); // which involves flush()
164 renderContext_->SwapBuffers(eglSurface_);
165
166 int rdcnum = 0;
167 std::string path = "/data/autocaps";
168 // Checks if the folder exists
169 if (!fs::exists(path)) {
170 continue;
171 }
172 for (const std::filesystem::directory_entry& entry : std::filesystem::directory_iterator(path)) {
173 const std::filesystem::path& path = entry.path();
174 if (path.extension() == ".rdc") {
175 rdcnum++;
176 }
177 }
178 if (rdcnum > 0) {
179 // it means the .rdc capture is saved succesfully and further handled by the RsProfiler
180 return true;
181 }
182 }
183 return false;
184 }
185
PrepareNativeEGLSetup()186 bool DrawingSampleReplayer::PrepareNativeEGLSetup()
187 {
188 renderContext_ = std::make_shared<RenderContext>();
189 renderContext_->InitializeEglContext();
190
191 auto defaultDisplay = DisplayManager::GetInstance().GetDefaultDisplay();
192 width_ = static_cast<uint32_t>(defaultDisplay->GetWidth());
193 height_ = static_cast<uint32_t>(defaultDisplay->GetHeight());
194
195 std::cout << "Width: " << width_ << " - Height: " << height_ << std::endl;
196
197 RSSurfaceNodeConfig surfaceNodeConfig = {"DrawingEngineSample"};
198 RSSurfaceNodeType surfaceNodeType = RSSurfaceNodeType::SELF_DRAWING_WINDOW_NODE;
199 surfaceNode_ = RSSurfaceNode::Create(surfaceNodeConfig, surfaceNodeType);
200 if (!surfaceNode_) {
201 std::cout << "surfaceNode is nullptr" << std::endl;
202 return false;
203 }
204
205 surfaceNode_->SetFrameGravity(Gravity::RESIZE_ASPECT_FILL);
206 surfaceNode_->SetPositionZ(RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
207 surfaceNode_->SetBounds(0, 0, width_, height_);
208 surfaceNode_->AttachToDisplay(defaultDisplayId_);
209 RSTransaction::FlushImplicitTransaction();
210
211 sptr<Surface> ohosSurface = surfaceNode_->GetSurface();
212 nativeWindow_ = CreateNativeWindowFromSurface(&ohosSurface);
213 if (nativeWindow_ == nullptr) {
214 std::cout << "CreateNativeWindowFromSurface Failed" << std::endl;
215 return false;
216 }
217
218 eglSurface_ = renderContext_->CreateEGLSurface((EGLNativeWindowType)nativeWindow_);
219 if (eglSurface_ == EGL_NO_SURFACE) {
220 std::cout << "Invalid eglSurface, return" << std::endl;
221 DestoryNativeWindow(nativeWindow_);
222 return false;
223 }
224
225 renderContext_->MakeCurrent(eglSurface_);
226 EGLint initRes = eglGetError();
227 if (initRes != EGL_SUCCESS) {
228 std::cout << "Fail to init egl" << std::endl;
229 DestoryNativeWindow(nativeWindow_);
230 return false;
231 }
232 NativeWindowHandleOpt(nativeWindow_, SET_BUFFER_GEOMETRY, width_, height_);
233 return true;
234 }
235
SetCaptureMode(CaptureMode mode)236 void DrawingSampleReplayer::SetCaptureMode(CaptureMode mode)
237 {
238 captureMode_ = mode;
239 }
240
241 } // namespace OHOS::Rosen
242
main(int32_t argc,char * argv[])243 int32_t main(int32_t argc, char *argv[])
244 {
245 OHOS::Rosen::DrawingSampleReplayer replayer;
246 std::string replayType = "default";
247 if (argc > 1) {
248 replayType = std::string(argv[1]);
249 if (replayType == "skp") {
250 replayer.SetCaptureMode(OHOS::Rosen::CaptureMode::SKP);
251 } else if (replayType == "rdc") {
252 replayer.SetCaptureMode(OHOS::Rosen::CaptureMode::RDC);
253 }
254 }
255 std::cout << "Mode: " << replayType << std::endl;
256 if (!replayer.PrepareNativeEGLSetup()) {
257 return -1;
258 }
259 if (!replayer.RenderLoop()) {
260 return -1;
261 }
262 return 0;
263 }
264