• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "rs_profiler_capture_recorder.h"
16 
17 #include <cstdio>
18 #include <cstdlib>
19 #include <cstring>
20 #include <filesystem>
21 #include <sstream>
22 
23 #include "common/rs_common_def.h"
24 #include "draw/canvas.h"
25 #include "pipeline/rs_recording_canvas.h"
26 #include "platform/common/rs_system_properties.h"
27 #include "transaction/rs_marshalling_helper.h"
28 
29 #include "rs_profiler_network.h"
30 #include "rs_profiler_packet.h"
31 #include "rs_profiler_settings.h"
32 #include "rs_profiler_utils.h"
33 
34 namespace OHOS::Rosen {
35 
36 bool RSCaptureRecorder::testingTriggering_ = false;
37 
38 static const Int32Parameter MSKP_COUNTER("mskp.counter");
39 static const Int32Parameter MSKP_MAX("mskp.max");
40 static const StringParameter MSKP_PATH("mskp.path");
41 static const BoolParameter IS_MSKP("mskp.isMskp");
42 
43 // 0 - default capturing from canvas in DisplayNode::OnDraw (which is used for imgCache via snapshot())
44 // 1 - capturing from mirroredDrawable::OnCapture() call in DisplayNode::DrawMirror + security/black screen
45 // 2 - capturing offscreen rendering in DisplayNode::OnDraw for extended screen
46 // 3 - capturing the actual drawing of imgCache as texture in DisplayNode::DrawMirrorCopy
47 static Uint32Parameter CAPTURE_TYPE("capture.type");
48 
PrintMessage(std::string message,bool forcedSend)49 bool RSCaptureRecorder::PrintMessage(std::string message, bool forcedSend)
50 {
51     if (RSSystemProperties::GetInstantRecording() || forcedSend) {
52         Network::SendMessage(message);
53         return true;
54     }
55     return false;
56 }
57 
RSCaptureRecorder()58 RSCaptureRecorder::RSCaptureRecorder()
59 {
60     profilerEnabled_ = RSSystemProperties::GetProfilerEnabled();
61     InvalidateDrawingCanvasNodeId();
62 }
63 
64 RSCaptureRecorder::~RSCaptureRecorder() = default;
65 
SetProfilerEnabled(bool val)66 void RSCaptureRecorder::SetProfilerEnabled(bool val)
67 {
68     profilerEnabled_ = val;
69 }
70 
IsRecordingEnabled()71 bool RSCaptureRecorder::IsRecordingEnabled()
72 {
73     return (profilerEnabled_ && RSSystemProperties::GetInstantRecording()) || testingTriggering_;
74 }
75 
InvalidateDrawingCanvasNodeId()76 void RSCaptureRecorder::InvalidateDrawingCanvasNodeId()
77 {
78     SetDrawingCanvasNodeId(INVALID_NODEID);
79 }
80 
SetDrawingCanvasNodeId(uint64_t nodeId)81 void RSCaptureRecorder::SetDrawingCanvasNodeId(uint64_t nodeId)
82 {
83     drawingCanvasNodeId_ = nodeId;
84 }
85 
SetComponentScreenshotFlag(bool flag)86 void RSCaptureRecorder::SetComponentScreenshotFlag(bool flag)
87 {
88     isComponentScreenshot_ = flag;
89 }
90 
SetCaptureType(SkpCaptureType type)91 void RSCaptureRecorder::SetCaptureType(SkpCaptureType type)
92 {
93     CAPTURE_TYPE = static_cast<uint32_t>(type);
94 }
95 
SetCaptureTypeClear(bool flag)96 void RSCaptureRecorder::SetCaptureTypeClear(bool flag)
97 {
98     captureTypeToClear_ = flag;
99 }
100 
TryInstantCapture(float width,float height,SkpCaptureType type)101 Drawing::Canvas* RSCaptureRecorder::TryInstantCapture(float width, float height, SkpCaptureType type)
102 {
103     if (!IsRecordingEnabled()) {
104         return nullptr;
105     }
106     if (RSSystemProperties::GetSaveRDC()) {
107         // for saving .drawing file
108         recordingTriggeredFullFrame_ = true;
109         return TryInstantCaptureDrawing(width, height);
110     }
111     // for saving .mskp file
112     mskpMaxLocal_ = *MSKP_MAX;
113     mskpIdxNext_ = *MSKP_COUNTER;
114 
115     if (*IS_MSKP) {
116         // record next frame, triggered by profiler step
117         if ((mskpIdxCurrent_ != mskpIdxNext_) && (mskpMaxLocal_ > 0)) {
118             recordingTriggeredFullFrame_ = true;
119             return TryCaptureMSKP(width, height);
120         }
121         return nullptr;
122     }
123     if (isMskpActive_) {
124         return nullptr;
125     }
126 
127     if (static_cast<uint32_t>(type) != CAPTURE_TYPE.Get()) {
128         return nullptr;
129     }
130 
131     // for saving .skp file
132     recordingTriggeredFullFrame_ = true;
133     return TryInstantCaptureSKP(width, height);
134 }
135 
EndInstantCapture(SkpCaptureType type)136 void RSCaptureRecorder::EndInstantCapture(SkpCaptureType type)
137 {
138     if (!(IsRecordingEnabled() && recordingTriggeredFullFrame_) && !isMskpActive_) {
139         return;
140     }
141     recordingTriggeredFullFrame_ = false;
142     if (RSSystemProperties::GetSaveRDC()) {
143         // for saving .drawing file
144         EndInstantCaptureDrawing();
145         return;
146     }
147     if (((mskpMaxLocal_ > 0) && isPageActive_) || isMskpActive_) {
148         recordingTriggeredFullFrame_ = false;
149         return EndCaptureMSKP();
150     }
151 
152     if (static_cast<uint32_t>(type) != CAPTURE_TYPE.Get()) {
153         return;
154     }
155 
156     // for saving .skp file
157     recordingTriggeredFullFrame_ = false;
158     Network::SendMessage("Finishing .skp capturing");
159     EndInstantCaptureSKP();
160 }
161 
TryDrawingCanvasCapture(float width,float height,uint64_t nodeId)162 Drawing::Canvas* RSCaptureRecorder::TryDrawingCanvasCapture(float width, float height, uint64_t nodeId)
163 {
164     if (drawingCanvasNodeId_ != nodeId) {
165         return nullptr;
166     }
167 
168     recordingTriggeredDrawingCanvas_ = true;
169     return TryInstantCaptureSKP(width, height);
170 }
171 
EndDrawingCanvasCapture()172 void RSCaptureRecorder::EndDrawingCanvasCapture()
173 {
174     if (!recordingTriggeredDrawingCanvas_) {
175         return;
176     }
177     recordingTriggeredDrawingCanvas_ = false;
178     EndInstantCaptureSKP();
179 }
180 
TryOffscreenCanvasCapture(float width,float height)181 Drawing::Canvas* RSCaptureRecorder::TryOffscreenCanvasCapture(float width, float height)
182 {
183     recordingTriggeredOffscreenCanvas_ = true;
184     return TryInstantCaptureSKP(width, height);
185 }
186 
EndOffscreenCanvasCapture()187 void RSCaptureRecorder::EndOffscreenCanvasCapture()
188 {
189     if (!recordingTriggeredOffscreenCanvas_) {
190         return;
191     }
192     recordingTriggeredOffscreenCanvas_ = false;
193     EndInstantCaptureSKP();
194 }
195 
TryComponentScreenshotCapture(float width,float height)196 Drawing::Canvas* RSCaptureRecorder::TryComponentScreenshotCapture(float width, float height)
197 {
198     if (!isComponentScreenshot_) {
199         return nullptr;
200     }
201     recordingTriggeredComponentScreenshot_ = true;
202     return TryInstantCaptureSKP(width, height);
203 }
204 
EndComponentScreenshotCapture()205 void RSCaptureRecorder::EndComponentScreenshotCapture()
206 {
207     if (!recordingTriggeredComponentScreenshot_) {
208         return;
209     }
210     recordingTriggeredComponentScreenshot_ = false;
211     EndInstantCaptureSKP();
212     SetComponentScreenshotFlag(false);
213 }
214 
GetDirtyRect(uint32_t displayWidth,uint32_t displayHeight)215 std::pair<uint32_t, uint32_t> RSCaptureRecorder::GetDirtyRect(uint32_t displayWidth, uint32_t displayHeight)
216 {
217     if (IsRecordingEnabled()) {
218         return std::pair<uint32_t, uint32_t>(displayWidth, displayHeight);
219     }
220     return std::pair<uint32_t, uint32_t>(0, 0);
221 }
222 
PullAndSendRdc()223 bool RSCaptureRecorder::PullAndSendRdc()
224 {
225     const std::string path("/data/autocaps");
226     if (!std::filesystem::exists(path)) {
227         return false;
228     }
229     std::vector<std::string> files;
230     for (const std::filesystem::directory_entry& entry : std::filesystem::directory_iterator(path)) {
231         const std::filesystem::path& path = entry.path();
232         if (path.extension() == ".rdc") {
233             files.emplace_back(path.generic_string());
234         }
235     }
236     const size_t filesRequired = 1;
237     if (files.size() == filesRequired) {
238         Network::SendRdcPath(files[0]);
239         return true;
240     }
241     return false;
242 }
243 
InitMSKP()244 void RSCaptureRecorder::InitMSKP()
245 {
246     auto stream = std::make_unique<Drawing::FileWStream>((*MSKP_PATH).data());
247     if (!stream->IsValid()) {
248         std::cout << "Could not open " << *MSKP_PATH << " for writing." << std::endl;
249         return;
250     }
251     openMultiPicStream_ = std::move(stream);
252 
253     serialContext_ = std::make_unique<Drawing::SharingSerialContext>();
254     Drawing::SerialProcs procs;
255     multiPic_ = Drawing::Document::MakeMultiPictureDocument(openMultiPicStream_.get(), &procs, serialContext_);
256     isMskpActive_ = true;
257 }
258 
TryInstantCaptureDrawing(float width,float height)259 ExtendRecordingCanvas* RSCaptureRecorder::TryInstantCaptureDrawing(float width, float height)
260 {
261     recordingCanvas_ = std::make_unique<ExtendRecordingCanvas>(width, height);
262     return recordingCanvas_.get();
263 }
264 
EndInstantCaptureDrawing()265 void RSCaptureRecorder::EndInstantCaptureDrawing()
266 {
267     auto drawCmdList = recordingCanvas_->GetDrawCmdList();
268 
269     const size_t recordingParcelCapacity = 234 * 1000 * 1024;
270     std::shared_ptr<MessageParcel> messageParcel = std::make_shared<MessageParcel>();
271     messageParcel->SetMaxCapacity(recordingParcelCapacity);
272     RSMarshallingHelper::BeginNoSharedMem(std::this_thread::get_id());
273     bool marshallingComplete = RSMarshallingHelper::Marshalling(*messageParcel, drawCmdList);
274     RSMarshallingHelper::EndNoSharedMem();
275 
276     if (!marshallingComplete) {
277         RSSystemProperties::SetInstantRecording(false);
278         return;
279     }
280 
281     size_t parcelSize = messageParcel->GetDataSize();
282     uintptr_t parcelBuf = messageParcel->GetData();
283 
284     // Create file and write the parcel
285     const std::string drawCmdListFilename = "/data/default.drawing";
286     FILE* f = Utils::FileOpen(drawCmdListFilename, "wbe");
287     if (f == nullptr) {
288         RSSystemProperties::SetInstantRecording(false);
289         return;
290     }
291     Utils::FileWrite(reinterpret_cast<uint8_t*>(parcelBuf), sizeof(uint8_t), parcelSize, f);
292     Utils::FileClose(f);
293 
294     Network::SendDclPath(drawCmdListFilename);
295     Network::SendMessage("Saved locally");
296     RSSystemProperties::SetInstantRecording(false);
297 }
298 
TryInstantCaptureSKP(float width,float height)299 Drawing::Canvas* RSCaptureRecorder::TryInstantCaptureSKP(float width, float height)
300 {
301     Network::SendMessage("Starting .skp capturing.");
302     recordingSkpCanvas_ = std::make_shared<Drawing::Canvas>(width, height);
303     recorder_ = std::make_unique<Drawing::PictureRecorder>();
304     auto canvas = recorder_->BeginRecording(width, height);
305     if (canvas == nullptr) {
306         return nullptr;
307     }
308     recordingSkpCanvas_ = canvas;
309     return recordingSkpCanvas_.get();
310 }
311 
EndInstantCaptureSKP()312 void RSCaptureRecorder::EndInstantCaptureSKP()
313 {
314     if (recorder_ == nullptr) {
315         RSSystemProperties::SetInstantRecording(false);
316         return;
317     }
318     InvalidateDrawingCanvasNodeId();
319     picture_ = recorder_->FinishRecordingAsPicture();
320     Network::SendMessage("Finishing .skp capturing.");
321     if (picture_ != nullptr) {
322         if (picture_->ApproximateOpCount() > 0) {
323             Network::SendMessage("OpCount: " + std::to_string(picture_->ApproximateOpCount()));
324             Drawing::SerialProcs procs;
325             procs.SetHasTypefaceProc(true);
326             auto data = picture_->Serialize(&procs);
327             if (data && (data->GetSize() > 0)) {
328                     Network::SendMessage("Sending SKP");
329                     Network::SendSkp(data->GetData(), data->GetSize());
330                 }
331         }
332     } else {
333         Network::SendMessage("Empty, nothing to record to .skp");
334     }
335     RSSystemProperties::SetInstantRecording(false);
336     if (captureTypeToClear_) {
337         SetCaptureType(SkpCaptureType::DEFAULT);
338         captureTypeToClear_ = false;
339     }
340 }
341 
TryCaptureMSKP(float width,float height)342 Drawing::Canvas* RSCaptureRecorder::TryCaptureMSKP(float width, float height)
343 {
344     if (!isMskpActive_) {
345         Network::SendMessage("Starting .mskp capturing.");
346         SetCaptureType(SkpCaptureType::DEFAULT);
347         InitMSKP();
348     }
349     mskpIdxCurrent_ = mskpIdxNext_;
350     recordingSkpCanvas_ = std::make_shared<Drawing::Canvas>(width, height);
351     std::shared_ptr<Drawing::Canvas> canvas = multiPic_->BeginPage(width, height);
352     Network::SendMessage("Begin .mskp page: " + std::to_string(mskpIdxCurrent_));
353     if (canvas == nullptr) {
354         return nullptr;
355     }
356     recordingSkpCanvas_ = canvas;
357     isPageActive_ = true;
358     return recordingSkpCanvas_.get();
359 }
360 
EndCaptureMSKP()361 void RSCaptureRecorder::EndCaptureMSKP()
362 {
363     if (isPageActive_) {
364         Network::SendMessage("Close .mskp page: " + std::to_string(mskpIdxCurrent_));
365         multiPic_->EndPage();
366     }
367     isPageActive_ = false;
368 
369     if (!*IS_MSKP || (mskpIdxNext_ == -1)) {
370         Network::SendMessage("Finishing / Serializing .mskp capturing");
371         RSSystemProperties::SetInstantRecording(false);
372         // setting to default
373         mskpMaxLocal_ = 0;
374         mskpIdxCurrent_ = -1;
375         mskpIdxNext_ = -1;
376         isMskpActive_ = false;
377 
378         std::thread thread([this]() mutable {
379             Drawing::FileWStream* stream = this->openMultiPicStream_.release();
380             Network::SendMessage("MSKP serialization started.");
381             this->multiPic_->Close();
382             Network::SendMessage("MSKP Serialization done.");
383             delete stream;
384             Network::SendMskpPath(*MSKP_PATH);
385         });
386         thread.detach();
387     }
388 }
389 
390 } // namespace OHOS::Rosen