• 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 
22 #include "benchmarks/file_utils.h"
23 #include "include/core/SkDocument.h"
24 #include "include/core/SkPicture.h"
25 #include "include/core/SkPictureRecorder.h"
26 #include "include/core/SkSerialProcs.h"
27 #include "include/core/SkStream.h"
28 #include "include/utils/SkNWayCanvas.h"
29 #include "src/utils/SkMultiPictureDocument.h"
30 #include "tools/SkSharingProc.h"
31 
32 #include "common/rs_common_def.h"
33 #include "draw/canvas.h"
34 #include "drawing/engine_adapter/skia_adapter/skia_canvas.h"
35 #include "pipeline/rs_recording_canvas.h"
36 #include "platform/common/rs_log.h"
37 #include "platform/common/rs_system_properties.h"
38 #include "transaction/rs_marshalling_helper.h"
39 
40 #include "rs_profiler_network.h"
41 #include "rs_profiler_packet.h"
42 #include "rs_profiler_settings.h"
43 #include "rs_profiler_utils.h"
44 
45 namespace OHOS::Rosen {
46 
47 static const Int32Parameter MSKP_COUNTER("mskp.counter");
48 static const Int32Parameter MSKP_MAX("mskp.max");
49 static const StringParameter MSKP_PATH("mskp.path");
50 
51 RSCaptureRecorder::RSCaptureRecorder() = default;
52 RSCaptureRecorder::~RSCaptureRecorder() = default;
53 
IsRecordingEnabled()54 bool RSCaptureRecorder::IsRecordingEnabled()
55 {
56     static const bool profilerEnabled = RSSystemProperties::GetProfilerEnabled();
57     return profilerEnabled && RSSystemProperties::GetInstantRecording();
58 }
59 
TryInstantCapture(float width,float height)60 Drawing::Canvas* RSCaptureRecorder::TryInstantCapture(float width, float height)
61 {
62     if (!IsRecordingEnabled()) {
63         return nullptr;
64     }
65     if (RSSystemProperties::GetSaveRDC()) {
66         // for saving .drawing file
67         recordingTriggered_ = true;
68         return TryInstantCaptureDrawing(width, height);
69     }
70     // for saving .mskp file
71     mskpMaxLocal_ = *MSKP_MAX;
72     mskpIdxNext_ = *MSKP_COUNTER;
73 
74     if (mskpMaxLocal_ > 0) {
75         // record next frame, triggered by profiler step
76         if (mskpIdxCurrent_ != mskpIdxNext_) {
77             recordingTriggered_ = true;
78             return TryCaptureMSKP(width, height);
79         }
80         return nullptr;
81     }
82     // for saving .skp file
83     recordingTriggered_ = true;
84     return TryInstantCaptureSKP(width, height);
85 }
86 
EndInstantCapture()87 void RSCaptureRecorder::EndInstantCapture()
88 {
89     if (!(IsRecordingEnabled() && recordingTriggered_)) {
90         return;
91     }
92     recordingTriggered_ = false;
93     if (RSSystemProperties::GetSaveRDC()) {
94         // for saving .drawing file
95         EndInstantCaptureDrawing();
96         return;
97     }
98     if (mskpMaxLocal_ > 0) {
99         if (isPageActive_) {
100             recordingTriggered_ = false;
101             return EndCaptureMSKP();
102         }
103         return;
104     }
105 
106     // for saving .skp file
107     recordingTriggered_ = false;
108     EndInstantCaptureSKP();
109 }
110 
GetDirtyRect(uint32_t displayWidth,uint32_t displayHeight)111 std::pair<uint32_t, uint32_t> RSCaptureRecorder::GetDirtyRect(uint32_t displayWidth, uint32_t displayHeight)
112 {
113     if (IsRecordingEnabled()) {
114         return std::pair<uint32_t, uint32_t>(displayWidth, displayHeight);
115     }
116     return std::pair<uint32_t, uint32_t>(0, 0);
117 }
118 
PullAndSendRdc()119 bool RSCaptureRecorder::PullAndSendRdc()
120 {
121     const std::string path("/data/autocaps");
122     if (!std::filesystem::exists(path)) {
123         return false;
124     }
125     std::vector<std::string> files;
126     for (const std::filesystem::directory_entry& entry : std::filesystem::directory_iterator(path)) {
127         const std::filesystem::path& path = entry.path();
128         if (path.extension() == ".rdc") {
129             files.emplace_back(path.generic_string());
130         }
131     }
132     const size_t filesRequired = 1;
133     if (files.size() == filesRequired) {
134         Network::SendRdcPath(files[0]);
135         return true;
136     }
137     return false;
138 }
139 
InitMSKP()140 void RSCaptureRecorder::InitMSKP()
141 {
142     auto stream = std::make_unique<SkFILEWStream>((*MSKP_PATH).data());
143     if (!stream->isValid()) {
144         std::cout << "Could not open " << *MSKP_PATH << " for writing." << std::endl;
145         return;
146     }
147     openMultiPicStream_ = std::move(stream);
148 
149     SkSerialProcs procs;
150     serialContext_ = std::make_unique<SkSharingSerialContext>();
151     procs.fImageProc = SkSharingSerialContext::serializeImage;
152     procs.fImageCtx = serialContext_.get();
153     procs.fTypefaceProc = [](SkTypeface* tf, void* ctx) {
154         return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
155     };
156     multiPic_ = SkMakeMultiPictureDocument(
157         openMultiPicStream_.get(), &procs, [sharingCtx = serialContext_.get()](const SkPicture* pic) {
158             SkSharingSerialContext::collectNonTextureImagesFromPicture(pic, sharingCtx);
159         });
160 }
161 
TryInstantCaptureDrawing(float width,float height)162 ExtendRecordingCanvas* RSCaptureRecorder::TryInstantCaptureDrawing(float width, float height)
163 {
164     recordingCanvas_ = std::make_unique<ExtendRecordingCanvas>(width, height);
165     return recordingCanvas_.get();
166 }
167 
EndInstantCaptureDrawing()168 void RSCaptureRecorder::EndInstantCaptureDrawing()
169 {
170     auto drawCmdList = recordingCanvas_->GetDrawCmdList();
171 
172     const size_t recordingParcelCapacity = 234 * 1000 * 1024;
173     std::shared_ptr<MessageParcel> messageParcel = std::make_shared<MessageParcel>();
174     messageParcel->SetMaxCapacity(recordingParcelCapacity);
175     RSMarshallingHelper::BeginNoSharedMem(std::this_thread::get_id());
176     bool marshallingComplete = RSMarshallingHelper::Marshalling(*messageParcel, drawCmdList);
177     RSMarshallingHelper::EndNoSharedMem();
178 
179     if (!marshallingComplete) {
180         RSSystemProperties::SetInstantRecording(false);
181         return;
182     }
183 
184     size_t parcelSize = messageParcel->GetDataSize();
185     uintptr_t parcelBuf = messageParcel->GetData();
186 
187     // Create file and write the parcel
188     const std::string drawCmdListFilename = "/data/default.drawing";
189     FILE* f = Utils::FileOpen(drawCmdListFilename, "wbe");
190     if (f == nullptr) {
191         RSSystemProperties::SetInstantRecording(false);
192         return;
193     }
194     Utils::FileWrite(reinterpret_cast<uint8_t*>(parcelBuf), sizeof(uint8_t), parcelSize, f);
195     Utils::FileClose(f);
196 
197     Network::SendDclPath(drawCmdListFilename);
198     Network::SendMessage("Saved locally");
199     RSSystemProperties::SetInstantRecording(false);
200 }
201 
TryInstantCaptureSKP(float width,float height)202 Drawing::Canvas* RSCaptureRecorder::TryInstantCaptureSKP(float width, float height)
203 {
204     Network::SendMessage("Starting .skp capturing.");
205     recordingSkpCanvas_ = std::make_shared<Drawing::Canvas>(width, height);
206     skRecorder_ = std::make_unique<SkPictureRecorder>();
207     SkCanvas* skiaCanvas = skRecorder_->beginRecording(width, height);
208     if (skiaCanvas == nullptr) {
209         return nullptr;
210     }
211     recordingSkpCanvas_->GetImpl<Drawing::SkiaCanvas>()->ImportSkCanvas(skiaCanvas);
212     return recordingSkpCanvas_.get();
213 }
214 
EndInstantCaptureSKP()215 void RSCaptureRecorder::EndInstantCaptureSKP()
216 {
217     Network::SendMessage("Finishing .skp capturing");
218     if (skRecorder_ == nullptr) {
219         RSSystemProperties::SetInstantRecording(false);
220         return;
221     }
222     picture_ = skRecorder_->finishRecordingAsPicture();
223     if (picture_ != nullptr) {
224         if (picture_->approximateOpCount() > 0) {
225             Network::SendMessage("OpCount: " + std::to_string(picture_->approximateOpCount()));
226             SkSerialProcs procs;
227             procs.fTypefaceProc = [](SkTypeface* tf, void* ctx) {
228                 return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
229             };
230             auto data = picture_->serialize(&procs);
231             if (data && (data->size() > 0)) {
232                 Network::SendSkp(data->data(), data->size());
233             }
234         }
235     }
236     RSSystemProperties::SetInstantRecording(false);
237 }
238 
TryCaptureMSKP(float width,float height)239 Drawing::Canvas* RSCaptureRecorder::TryCaptureMSKP(float width, float height)
240 {
241     if (mskpIdxNext_ == 0) {
242         Network::SendMessage("Starting .mskp capturing.");
243         InitMSKP();
244     }
245     mskpIdxCurrent_ = mskpIdxNext_;
246     recordingSkpCanvas_ = std::make_shared<Drawing::Canvas>(width, height);
247     SkCanvas* skiaCanvas = multiPic_->beginPage(width, height);
248     Network::SendMessage("Begin .mskp page: " + std::to_string(mskpIdxCurrent_));
249     if (skiaCanvas == nullptr) {
250         return nullptr;
251     }
252     recordingSkpCanvas_->GetImpl<Drawing::SkiaCanvas>()->ImportSkCanvas(skiaCanvas);
253     isPageActive_ = true;
254     return recordingSkpCanvas_.get();
255 }
256 
EndCaptureMSKP()257 void RSCaptureRecorder::EndCaptureMSKP()
258 {
259     Network::SendMessage("Close .mskp page: " + std::to_string(mskpIdxCurrent_));
260     multiPic_->endPage();
261     isPageActive_ = false;
262 
263     if (mskpIdxCurrent_ == mskpMaxLocal_) {
264         Network::SendMessage("Finishing / Serializing .mskp capturing");
265         RSSystemProperties::SetInstantRecording(false);
266         // setting to default
267         mskpMaxLocal_ = 0;
268         mskpIdxCurrent_ = -1;
269         mskpIdxNext_ = -1;
270 
271         std::thread thread([this]() mutable {
272             SkFILEWStream* stream = this->openMultiPicStream_.release();
273             Network::SendMessage("MSKP serialization started.");
274             this->multiPic_->close();
275             Network::SendMessage("MSKP Serialization done.");
276             delete stream;
277             Network::SendMskpPath(*MSKP_PATH);
278         });
279         thread.detach();
280     }
281 }
282 
283 } // namespace OHOS::Rosen