1 /*
2 * Copyright (c) 2023 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 "benchmarks/rs_recording_thread.h"
17
18 #include <thread>
19 #include "common/rs_thread_handler.h"
20 #include "platform/common/rs_system_properties.h"
21 #include "platform/common/rs_log.h"
22 #include "rs_trace.h"
23 #include "transaction/rs_marshalling_helper.h"
24 #ifdef RS_ENABLE_VK
25 #include "platform/ohos/backend/rs_vulkan_context.h"
26 #endif
27
28 namespace OHOS::Rosen {
~RSRecordingThread()29 RSRecordingThread::~RSRecordingThread()
30 {
31 RS_LOGI("RSRecordingThread::~RSRecordingThread()");
32 PostTask([this]() {
33 DestroyShareEglContext();
34 });
35 }
36
Instance(RenderContext * context)37 RSRecordingThread &RSRecordingThread::Instance(RenderContext* context)
38 {
39 static RSRecordingThread instance(context);
40 return instance;
41 }
42
Start()43 void RSRecordingThread::Start()
44 {
45 runner_ = AppExecFwk::EventRunner::Create("RSRecordingThread");
46 handler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
47 PostTask([this]() {
48 grContext_ = CreateShareGrContext();
49 });
50 }
51
52 #ifndef USE_ROSEN_DRAWING
53 #ifdef NEW_SKIA
CreateShareGrContext()54 sk_sp<GrDirectContext> RSRecordingThread::CreateShareGrContext()
55 #else
56 sk_sp<GrContext> RSRecordingThread::CreateShareGrContext()
57 #endif
58 {
59 RS_TRACE_NAME("RSRecordingThread::CreateShareGrContext");
60 #ifdef RS_ENABLE_GL
61 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
62 CreateShareEglContext();
63 const GrGLInterface *grGlInterface = GrGLCreateNativeInterface();
64 sk_sp<const GrGLInterface> glInterface(grGlInterface);
65 if (glInterface.get() == nullptr) {
66 RS_LOGE("CreateShareGrContext failed");
67 return nullptr;
68 }
69
70 GrContextOptions options = {};
71 options.fGpuPathRenderers &= ~GpuPathRenderers::kCoverageCounting;
72 // fix svg antialiasing bug
73 options.fGpuPathRenderers &= ~GpuPathRenderers::kAtlas;
74 options.fPreferExternalImagesOverES3 = true;
75 options.fDisableDistanceFieldPaths = true;
76
77 auto handler = std::make_shared<MemoryHandler>();
78 auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
79 auto size = glesVersion ? strlen(glesVersion) : 0;
80 handler->ConfigureContext(&options, glesVersion, size);
81
82 #ifdef NEW_SKIA
83 sk_sp<GrDirectContext> grContext = GrDirectContext::MakeGL(std::move(glInterface), options);
84 #else
85 sk_sp<GrContext> grContext = GrContext::MakeGL(std::move(glInterface), options);
86 #endif
87 if (grContext == nullptr) {
88 RS_LOGE("nullptr grContext is null");
89 return nullptr;
90 }
91 return grContext;
92 }
93 #endif
94
95 #ifdef RS_ENABLE_VK
96 if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
97 RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
98 sk_sp<GrDirectContext> grContext = GrDirectContext::MakeVulkan(
99 RsVulkanContext::GetSingleton().GetGrVkBackendContext());
100 if (grContext == nullptr) {
101 RS_LOGE("nullptr grContext is null");
102 return nullptr;
103 }
104 return grContext;
105 }
106 #endif
107 return nullptr;
108 }
109 #else
CreateShareGrContext()110 std::shared_ptr<Drawing::GPUContext> RSRecordingThread::CreateShareGrContext()
111 {
112 RS_TRACE_NAME("CreateShareGrContext");
113 auto gpuContext = std::make_shared<Drawing::GPUContext>();
114 #ifdef RS_ENABLE_GL
115 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
116 CreateShareEglContext();
117 Drawing::GPUContextOptions options;
118 auto handler = std::make_shared<MemoryHandler>();
119 auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
120 auto size = glesVersion ? strlen(glesVersion) : 0;
121 handler->ConfigureContext(&options, glesVersion, size);
122 if (!gpuContext->BuildFromGL(options)) {
123 RS_LOGE("nullptr gpuContext is null");
124 return nullptr;
125 }
126 return gpuContext;
127 }
128 #endif
129 #ifdef RS_ENABLE_VK
130 if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
131 RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
132 Drawing::GPUContextOptions options;
133 auto handler = std::make_shared<MemoryHandler>();
134 std::string vulkanVersion = RsVulkanContext::GetSingleton().GetVulkanVersion();
135 auto size = vulkanVersion.size();
136 handler->ConfigureContext(&options, vulkanVersion.c_str(), size);
137 if (!gpuContext->BuildFromVK(RsVulkanContext::GetSingleton().GetGrVkBackendContext(), options)) {
138 RS_LOGE("nullptr gpuContext is null");
139 return nullptr;
140 }
141 return gpuContext;
142 }
143 #endif
144 return nullptr;
145 }
146 #endif
147
CreateShareEglContext()148 void RSRecordingThread::CreateShareEglContext()
149 {
150 if (renderContext_ == nullptr) {
151 RS_LOGE("renderContext_ is nullptr");
152 return;
153 }
154 #ifdef RS_ENABLE_GL
155 if (RSSystemProperties::GetGpuApiType() != GpuApiType::OPENGL) {
156 return;
157 }
158 eglShareContext_ = renderContext_->CreateShareContext();
159 if (eglShareContext_ == EGL_NO_CONTEXT) {
160 RS_LOGE("eglShareContext_ is EGL_NO_CONTEXT");
161 return;
162 }
163 if (!eglMakeCurrent(renderContext_->GetEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, eglShareContext_)) {
164 RS_LOGE("eglMakeCurrent failed");
165 return;
166 }
167 #endif
168 }
169
DestroyShareEglContext()170 void RSRecordingThread::DestroyShareEglContext()
171 {
172 #ifdef RS_ENABLE_GL
173 if (RSSystemProperties::GetGpuApiType() != GpuApiType::OPENGL) {
174 return;
175 }
176 if (renderContext_ != nullptr) {
177 eglDestroyContext(renderContext_->GetEGLDisplay(), eglShareContext_);
178 eglShareContext_ = EGL_NO_CONTEXT;
179 eglMakeCurrent(renderContext_->GetEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
180 }
181 #endif
182 }
IsIdle()183 bool RSRecordingThread::IsIdle()
184 {
185 return handler_ && handler_->IsIdle();
186 }
187
PostTask(const std::function<void ()> & task)188 void RSRecordingThread::PostTask(const std::function<void()> &task)
189 {
190 if (handler_) {
191 handler_->PostTask(task, AppExecFwk::EventQueue::Priority::IMMEDIATE);
192 }
193 }
194
CheckAndRecording()195 bool RSRecordingThread::CheckAndRecording()
196 {
197 if (!handler_) {
198 Start();
199 }
200 RSTaskMessage::RSTask task = [this]() {
201 std::string line = "RSRecordingThread::CheckAndRecording curDumpFrame = " + std::to_string(curDumpFrame_) +
202 ", dumpFrameNum = " + std::to_string(dumpFrameNum_);
203 RS_LOGD("%{public}s", line.c_str());
204 mode_ = RecordingMode(RSSystemProperties::GetRecordingEnabled());
205 // init curDumpFrame
206 if (GetRecordingEnabled() && curDumpFrame_ == 0) {
207 RS_TRACE_NAME(line);
208 dumpFrameNum_ = RSSystemProperties::GetDumpFrameNum();
209 fileDir_ = RSSystemProperties::GetRecordingFile();
210 if (access(fileDir_.c_str(), F_OK) != 0) {
211 mkdir(fileDir_.c_str(), (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH));
212 }
213 }
214 };
215 PostTask(task);
216 return GetRecordingEnabled();
217 }
218
FinishRecordingOneFrameTask(RecordingMode modeSubThread)219 void RSRecordingThread::FinishRecordingOneFrameTask(RecordingMode modeSubThread)
220 {
221 for (int curFrameIndex = 0; curFrameIndex < dumpFrameNum_; curFrameIndex++) {
222 std::shared_ptr<MessageParcel> messageParcel = std::make_shared<MessageParcel>();
223 std::string opsDescription = "drawing ops no description";
224 if (modeSubThread == RecordingMode::HIGH_SPPED_RECORDING) {
225 RS_LOGI("RSRecordingThread::High speed!");
226 messageParcel->SetMaxCapacity(RECORDING_PARCEL_CAPCITY);
227 RSMarshallingHelper::BeginNoSharedMem(std::this_thread::get_id());
228 #ifndef USE_ROSEN_DRAWING
229 drawCmdListVec_[curFrameIndex]->Marshalling(*messageParcel);
230 #else
231 RSMarshallingHelper::Marshalling(*messageParcel, drawCmdListVec_[curFrameIndex]);
232 #endif
233 RSMarshallingHelper::EndNoSharedMem();
234 opsDescription = drawCmdListVec_[curFrameIndex]-> GetOpsWithDesc();
235 } else if (modeSubThread == RecordingMode::LOW_SPEED_RECORDING) {
236 messageParcel = messageParcelVec_[curFrameIndex];
237 opsDescription = opsDescriptionVec_[curFrameIndex];
238 }
239 OHOS::Rosen::Benchmarks::WriteMessageParcelToFile(messageParcel, opsDescription, curFrameIndex, fileDir_);
240 }
241 drawCmdListVec_.clear();
242 messageParcelVec_.clear();
243 opsDescriptionVec_.clear();
244 curDumpFrame_ = 0;
245 dumpFrameNum_ = 0;
246 fileDir_ = "";
247 RSSystemProperties::SetRecordingDisenabled();
248 RS_LOGD("RSRecordingThread::FinishRecordingOneFrame isRecordingEnabled = false");
249 }
250
FinishRecordingOneFrame()251 void RSRecordingThread::FinishRecordingOneFrame()
252 {
253 std::string line = "RSRecordingThread::FinishRecordingOneFrame curDumpFrame = " + std::to_string(curDumpFrame_) +
254 ", dumpFrameNum = " + std::to_string(dumpFrameNum_);
255 RS_LOGD("%{public}s", line.c_str());
256 RS_TRACE_NAME(line);
257 if (curDumpFrame_ < dumpFrameNum_) {
258 curDumpFrame_++;
259 return;
260 }
261 auto modeSubThread = mode_;
262 mode_ = RecordingMode::STOP_RECORDING;
263 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
264 RSTaskMessage::RSTask task = [this, modeSubThread]() {
265 FinishRecordingOneFrameTask(modeSubThread);
266 };
267 PostTask(task);
268 #else
269 FinishRecordingOneFrameTask(modeSubThread);
270 #endif
271 }
272
273 #ifndef USE_ROSEN_DRAWING
RecordingToFile(const std::shared_ptr<DrawCmdList> & drawCmdList)274 void RSRecordingThread::RecordingToFile(const std::shared_ptr<DrawCmdList>& drawCmdList)
275 #else
276 void RSRecordingThread::RecordingToFile(const std::shared_ptr<Drawing::DrawCmdList>& drawCmdList)
277 #endif
278 {
279 if (curDumpFrame_ < 0) {
280 return;
281 }
282 if (mode_ == RecordingMode::HIGH_SPPED_RECORDING) {
283 drawCmdListVec_.push_back(drawCmdList);
284 } else if (mode_ == RecordingMode::LOW_SPEED_RECORDING) {
285 #ifndef USE_ROSEN_DRAWING
286 std::shared_ptr<MessageParcel> messageParcel = std::make_shared<MessageParcel>();
287 messageParcel->SetMaxCapacity(RECORDING_PARCEL_CAPCITY);
288 RSMarshallingHelper::BeginNoSharedMem(std::this_thread::get_id());
289 drawCmdList->Marshalling(*messageParcel);
290 RSMarshallingHelper::EndNoSharedMem();
291 opsDescriptionVec_.push_back(drawCmdList->GetOpsWithDesc());
292 messageParcelVec_.push_back(messageParcel);
293 #else
294 std::shared_ptr<MessageParcel> messageParcel = std::make_shared<MessageParcel>();
295 messageParcel->SetMaxCapacity(RECORDING_PARCEL_CAPCITY);
296 RSMarshallingHelper::BeginNoSharedMem(std::this_thread::get_id());
297 RSMarshallingHelper::Marshalling(*messageParcel, drawCmdList);
298 RSMarshallingHelper::EndNoSharedMem();
299 opsDescriptionVec_.push_back(drawCmdList->GetOpsWithDesc());
300 messageParcelVec_.push_back(messageParcel);
301 #endif
302 }
303
304 FinishRecordingOneFrame();
305 }
306 }
307