1 // Copyright (C) 2020 The Android Open Source Project
2 //
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 "LocalPrebuiltGraph.h"
16
17 #include <android-base/logging.h>
18 #include <dlfcn.h>
19
20 #include <functional>
21 #include <iostream>
22 #include <mutex>
23 #include <shared_mutex>
24 #include <string>
25 #include <vector>
26
27 #include "ClientConfig.pb.h"
28 #include "InputFrame.h"
29 #include "PrebuiltGraph.h"
30 #include "RunnerComponent.h"
31 #include "prebuilt_interface.h"
32 #include "types/Status.h"
33
34 namespace android {
35 namespace automotive {
36 namespace computepipe {
37 namespace graph {
38
39 #define LOAD_FUNCTION(name) \
40 { \
41 std::string func_name = std::string("PrebuiltComputepipeRunner_") + #name; \
42 mPrebuiltGraphInstance->mFn##name = \
43 dlsym(mPrebuiltGraphInstance->mHandle, func_name.c_str()); \
44 if (mPrebuiltGraphInstance->mFn##name == nullptr) { \
45 initialized = false; \
46 LOG(ERROR) << std::string(dlerror()) << std::endl; \
47 } \
48 }
49
50 std::mutex LocalPrebuiltGraph::mCreationMutex;
51 LocalPrebuiltGraph* LocalPrebuiltGraph::mPrebuiltGraphInstance = nullptr;
52
53 // Function to confirm that there would be no further changes to the graph configuration. This
54 // needs to be called before starting the graph.
handleConfigPhase(const runner::ClientConfig & e)55 Status LocalPrebuiltGraph::handleConfigPhase(const runner::ClientConfig& e) {
56 if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
57 return Status::ILLEGAL_STATE;
58 }
59
60 // handleConfigPhase is a blocking call, so abort call is pointless for this RunnerEvent.
61 if (e.isAborted()) {
62 return Status::INVALID_ARGUMENT;
63 } else if (e.isTransitionComplete()) {
64 return Status::SUCCESS;
65 }
66
67 std::string config = e.getSerializedClientConfig();
68 auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(const unsigned char*,
69 size_t))mFnUpdateGraphConfig;
70 PrebuiltComputepipeRunner_ErrorCode errorCode =
71 mappedFn(reinterpret_cast<const unsigned char*>(config.c_str()), config.length());
72 if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
73 return static_cast<Status>(static_cast<int>(errorCode));
74 }
75
76 // Set the pixel stream callback function. The same function will be called for all requested
77 // pixel output streams.
78 if (mEngineInterface.lock() != nullptr) {
79 auto pixelCallbackFn = (PrebuiltComputepipeRunner_ErrorCode(*)(
80 void (*)(void* cookie, int, int64_t, const uint8_t* pixels, int width, int height,
81 int step, int format)))mFnSetOutputPixelStreamCallback;
82 PrebuiltComputepipeRunner_ErrorCode errorCode =
83 pixelCallbackFn(LocalPrebuiltGraph::OutputPixelStreamCallbackFunction);
84 if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
85 return static_cast<Status>(static_cast<int>(errorCode));
86 }
87
88 // Set the serialized stream callback function. The same callback function will be invoked
89 // for all requested serialized output streams.
90 auto streamCallbackFn = (PrebuiltComputepipeRunner_ErrorCode(*)(
91 void (*)(void* cookie, int, int64_t, const unsigned char*,
92 size_t)))mFnSetOutputStreamCallback;
93 errorCode = streamCallbackFn(LocalPrebuiltGraph::OutputStreamCallbackFunction);
94 if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
95 return static_cast<Status>(static_cast<int>(errorCode));
96 }
97
98 // Set the callback function for when the graph terminates.
99 auto terminationCallback = (PrebuiltComputepipeRunner_ErrorCode(*)(
100 void (*)(void* cookie, const unsigned char*,
101 size_t)))mFnSetGraphTerminationCallback;
102 errorCode = terminationCallback(LocalPrebuiltGraph::GraphTerminationCallbackFunction);
103 if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
104 return static_cast<Status>(static_cast<int>(errorCode));
105 }
106 }
107
108 return Status::SUCCESS;
109 }
110
111 // Starts the graph.
handleExecutionPhase(const runner::RunnerEvent & e)112 Status LocalPrebuiltGraph::handleExecutionPhase(const runner::RunnerEvent& e) {
113 if (mGraphState.load() != PrebuiltGraphState::STOPPED) {
114 return Status::ILLEGAL_STATE;
115 }
116
117 if (e.isAborted()) {
118 // Starting the graph is a blocking call and cannot be aborted in between.
119 return Status::INVALID_ARGUMENT;
120 } else if (e.isTransitionComplete()) {
121 return Status::SUCCESS;
122 }
123
124 auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(void*))mFnStartGraphExecution;
125 PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn(reinterpret_cast<void*>(this));
126 if (errorCode == PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
127 mGraphState.store(PrebuiltGraphState::RUNNING);
128 }
129 return static_cast<Status>(static_cast<int>(errorCode));
130 }
131
132 // Stops the graph while letting the graph flush output packets in flight.
handleStopWithFlushPhase(const runner::RunnerEvent & e)133 Status LocalPrebuiltGraph::handleStopWithFlushPhase(const runner::RunnerEvent& e) {
134 if (mGraphState.load() != PrebuiltGraphState::RUNNING) {
135 return Status::ILLEGAL_STATE;
136 }
137
138 if (e.isAborted()) {
139 return Status::INVALID_ARGUMENT;
140 } else if (e.isTransitionComplete()) {
141 return Status::SUCCESS;
142 }
143
144 return StopGraphExecution(/* flushOutputFrames = */ true);
145 }
146
147 // Stops the graph and cancels all the output packets.
handleStopImmediatePhase(const runner::RunnerEvent & e)148 Status LocalPrebuiltGraph::handleStopImmediatePhase(const runner::RunnerEvent& e) {
149 if (mGraphState.load() != PrebuiltGraphState::RUNNING) {
150 return Status::ILLEGAL_STATE;
151 }
152
153 if (e.isAborted()) {
154 return Status::INVALID_ARGUMENT;
155 } else if (e.isTransitionComplete()) {
156 return Status::SUCCESS;
157 }
158
159 return StopGraphExecution(/* flushOutputFrames = */ false);
160 }
161
handleResetPhase(const runner::RunnerEvent & e)162 Status LocalPrebuiltGraph::handleResetPhase(const runner::RunnerEvent& e) {
163 if (mGraphState.load() != PrebuiltGraphState::STOPPED) {
164 return Status::ILLEGAL_STATE;
165 }
166
167 if (e.isAborted()) {
168 return Status::INVALID_ARGUMENT;
169 } else if (e.isTransitionComplete()) {
170 return Status::SUCCESS;
171 }
172
173 auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)())mFnResetGraph;
174 mappedFn();
175 return Status::SUCCESS;
176 }
177
GetPrebuiltGraphFromLibrary(const std::string & prebuilt_library,std::weak_ptr<PrebuiltEngineInterface> engineInterface)178 LocalPrebuiltGraph* LocalPrebuiltGraph::GetPrebuiltGraphFromLibrary(
179 const std::string& prebuilt_library,
180 std::weak_ptr<PrebuiltEngineInterface> engineInterface) {
181 std::unique_lock<std::mutex> lock(LocalPrebuiltGraph::mCreationMutex);
182 if (mPrebuiltGraphInstance != nullptr) {
183 mPrebuiltGraphInstance = new LocalPrebuiltGraph();
184 }
185 if (mPrebuiltGraphInstance->mGraphState.load() != PrebuiltGraphState::UNINITIALIZED) {
186 return mPrebuiltGraphInstance;
187 }
188 mPrebuiltGraphInstance->mHandle = dlopen(prebuilt_library.c_str(), RTLD_NOW);
189
190 if (mPrebuiltGraphInstance->mHandle) {
191 bool initialized = true;
192
193 // Load config and version number first.
194 const unsigned char* (*getVersionFn)() =
195 (const unsigned char* (*)())dlsym(mPrebuiltGraphInstance->mHandle,
196 "PrebuiltComputepipeRunner_GetVersion");
197 if (getVersionFn != nullptr) {
198 mPrebuiltGraphInstance->mGraphVersion =
199 std::string(reinterpret_cast<const char*>(getVersionFn()));
200 } else {
201 LOG(ERROR) << std::string(dlerror());
202 initialized = false;
203 }
204
205 void (*getSupportedGraphConfigsFn)(const void**, size_t*) =
206 (void (*)(const void**,
207 size_t*))dlsym(mPrebuiltGraphInstance->mHandle,
208 "PrebuiltComputepipeRunner_GetSupportedGraphConfigs");
209 if (getSupportedGraphConfigsFn != nullptr) {
210 size_t graphConfigSize;
211 const void* graphConfig;
212
213 getSupportedGraphConfigsFn(&graphConfig, &graphConfigSize);
214
215 if (graphConfigSize > 0) {
216 initialized &= mPrebuiltGraphInstance->mGraphConfig.ParseFromString(
217 std::string(reinterpret_cast<const char*>(graphConfig), graphConfigSize));
218 }
219 } else {
220 LOG(ERROR) << std::string(dlerror());
221 initialized = false;
222 }
223
224 // Null callback interface is not acceptable.
225 if (initialized && engineInterface.lock() == nullptr) {
226 initialized = false;
227 }
228
229 LOAD_FUNCTION(GetErrorCode);
230 LOAD_FUNCTION(GetErrorMessage);
231 LOAD_FUNCTION(ResetGraph);
232 LOAD_FUNCTION(UpdateGraphConfig);
233 LOAD_FUNCTION(SetInputStreamData);
234 LOAD_FUNCTION(SetInputStreamPixelData);
235 LOAD_FUNCTION(SetOutputStreamCallback);
236 LOAD_FUNCTION(SetOutputPixelStreamCallback);
237 LOAD_FUNCTION(SetGraphTerminationCallback);
238 LOAD_FUNCTION(StartGraphExecution);
239 LOAD_FUNCTION(StopGraphExecution);
240 LOAD_FUNCTION(StartGraphProfiling);
241 LOAD_FUNCTION(StopGraphProfiling);
242 LOAD_FUNCTION(GetDebugInfo);
243
244 // This is the only way to create this object and there is already a
245 // lock around object creation, so no need to hold the graphState lock
246 // here.
247 if (initialized) {
248 mPrebuiltGraphInstance->mGraphState.store(PrebuiltGraphState::STOPPED);
249 mPrebuiltGraphInstance->mEngineInterface = engineInterface;
250 }
251 }
252
253 return mPrebuiltGraphInstance;
254 }
255
~LocalPrebuiltGraph()256 LocalPrebuiltGraph::~LocalPrebuiltGraph() {
257 if (mHandle) {
258 dlclose(mHandle);
259 }
260 }
261
GetStatus() const262 Status LocalPrebuiltGraph::GetStatus() const {
263 if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
264 return Status::ILLEGAL_STATE;
265 }
266
267 auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)())mFnGetErrorCode;
268 PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn();
269 return static_cast<Status>(static_cast<int>(errorCode));
270 }
271
GetErrorMessage() const272 std::string LocalPrebuiltGraph::GetErrorMessage() const {
273 if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
274 return "Graph has not been initialized";
275 }
276 auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(unsigned char*, size_t,
277 size_t*))mFnGetErrorMessage;
278 size_t errorMessageSize = 0;
279
280 PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn(nullptr, 0, &errorMessageSize);
281 std::vector<unsigned char> errorMessage(errorMessageSize);
282
283 errorCode = mappedFn(&errorMessage[0], errorMessage.size(), &errorMessageSize);
284 if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
285 return "Unable to get error message from the graph.";
286 }
287
288 return std::string(reinterpret_cast<char*>(&errorMessage[0]),
289 reinterpret_cast<char*>(&errorMessage[0]) + errorMessage.size());
290 }
291
SetInputStreamData(int streamIndex,int64_t timestamp,const std::string & streamData)292 Status LocalPrebuiltGraph::SetInputStreamData(int streamIndex, int64_t timestamp,
293 const std::string& streamData) {
294 if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
295 return Status::ILLEGAL_STATE;
296 }
297 auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(int, int64_t, const unsigned char*,
298 size_t))mFnSetInputStreamData;
299 PrebuiltComputepipeRunner_ErrorCode errorCode =
300 mappedFn(streamIndex, timestamp,
301 reinterpret_cast<const unsigned char*>(streamData.c_str()),
302 streamData.length());
303 return static_cast<Status>(static_cast<int>(errorCode));
304 }
305
SetInputStreamPixelData(int streamIndex,int64_t timestamp,const runner::InputFrame & inputFrame)306 Status LocalPrebuiltGraph::SetInputStreamPixelData(int streamIndex, int64_t timestamp,
307 const runner::InputFrame& inputFrame) {
308 if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
309 return Status::ILLEGAL_STATE;
310 }
311
312 auto mappedFn =
313 (PrebuiltComputepipeRunner_ErrorCode(*)(int, int64_t, const uint8_t*, int, int, int,
314 PrebuiltComputepipeRunner_PixelDataFormat))
315 mFnSetInputStreamPixelData;
316 PrebuiltComputepipeRunner_ErrorCode errorCode =
317 mappedFn(streamIndex, timestamp, inputFrame.getFramePtr(),
318 inputFrame.getFrameInfo().width, inputFrame.getFrameInfo().height,
319 inputFrame.getFrameInfo().stride,
320 static_cast<PrebuiltComputepipeRunner_PixelDataFormat>(
321 static_cast<int>(inputFrame.getFrameInfo().format)));
322 return static_cast<Status>(static_cast<int>(errorCode));
323 }
324
StopGraphExecution(bool flushOutputFrames)325 Status LocalPrebuiltGraph::StopGraphExecution(bool flushOutputFrames) {
326 auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(bool))mFnStopGraphExecution;
327 PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn(flushOutputFrames);
328 if (errorCode == PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
329 mGraphState.store(flushOutputFrames ? PrebuiltGraphState::FLUSHING
330 : PrebuiltGraphState::STOPPED);
331 }
332 return static_cast<Status>(static_cast<int>(errorCode));
333 }
334
StartGraphProfiling()335 Status LocalPrebuiltGraph::StartGraphProfiling() {
336 auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)())mFnStartGraphProfiling;
337 PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn();
338 return static_cast<Status>(static_cast<int>(errorCode));
339 }
340
StopGraphProfiling()341 Status LocalPrebuiltGraph::StopGraphProfiling() {
342 auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)())mFnStopGraphProfiling;
343 PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn();
344 return static_cast<Status>(static_cast<int>(errorCode));
345 }
346
GetDebugInfo()347 std::string LocalPrebuiltGraph::GetDebugInfo() {
348 if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
349 return "";
350 }
351 auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(unsigned char*, size_t,
352 size_t*))mFnGetDebugInfo;
353
354 size_t debugInfoSize = 0;
355 PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn(nullptr, 0, &debugInfoSize);
356 std::vector<unsigned char> debugInfo(debugInfoSize);
357
358 errorCode = mappedFn(&debugInfo[0], debugInfo.size(), &debugInfoSize);
359 if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
360 return "";
361 }
362
363 return std::string(reinterpret_cast<char*>(&debugInfo[0]),
364 reinterpret_cast<char*>(&debugInfo[0]) + debugInfo.size());
365 }
366
OutputStreamCallbackFunction(void * cookie,int streamIndex,int64_t timestamp,const unsigned char * data,size_t data_size)367 void LocalPrebuiltGraph::OutputStreamCallbackFunction(void* cookie, int streamIndex,
368 int64_t timestamp, const unsigned char* data,
369 size_t data_size) {
370 LocalPrebuiltGraph* graph = reinterpret_cast<LocalPrebuiltGraph*>(cookie);
371 CHECK(graph);
372 std::shared_ptr<PrebuiltEngineInterface> engineInterface = graph->mEngineInterface.lock();
373 if (engineInterface != nullptr) {
374 engineInterface->DispatchSerializedData(streamIndex, timestamp,
375 std::string(data, data + data_size));
376 }
377 }
378
OutputPixelStreamCallbackFunction(void * cookie,int streamIndex,int64_t timestamp,const uint8_t * pixels,int width,int height,int step,int format)379 void LocalPrebuiltGraph::OutputPixelStreamCallbackFunction(void* cookie, int streamIndex,
380 int64_t timestamp, const uint8_t* pixels,
381 int width, int height, int step,
382 int format) {
383 LocalPrebuiltGraph* graph = reinterpret_cast<LocalPrebuiltGraph*>(cookie);
384 CHECK(graph);
385 std::shared_ptr<PrebuiltEngineInterface> engineInterface = graph->mEngineInterface.lock();
386
387 if (engineInterface) {
388 runner::InputFrame frame(height, width, static_cast<PixelFormat>(format), step, pixels);
389 engineInterface->DispatchPixelData(streamIndex, timestamp, frame);
390 }
391 }
392
GraphTerminationCallbackFunction(void * cookie,const unsigned char * termination_message,size_t termination_message_size)393 void LocalPrebuiltGraph::GraphTerminationCallbackFunction(void* cookie,
394 const unsigned char* termination_message,
395 size_t termination_message_size) {
396 LocalPrebuiltGraph* graph = reinterpret_cast<LocalPrebuiltGraph*>(cookie);
397 CHECK(graph);
398 std::shared_ptr<PrebuiltEngineInterface> engineInterface = graph->mEngineInterface.lock();
399
400 if (engineInterface) {
401 std::string errorMessage = "";
402 if (termination_message != nullptr && termination_message_size > 0) {
403 std::string(termination_message, termination_message + termination_message_size);
404 }
405 graph->mGraphState.store(PrebuiltGraphState::STOPPED);
406 engineInterface->DispatchGraphTerminationMessage(graph->GetStatus(),
407 std::move(errorMessage));
408 }
409 }
410
GetLocalGraphFromLibrary(const std::string & prebuilt_library,std::weak_ptr<PrebuiltEngineInterface> engineInterface)411 PrebuiltGraph* GetLocalGraphFromLibrary(const std::string& prebuilt_library,
412 std::weak_ptr<PrebuiltEngineInterface> engineInterface) {
413 return LocalPrebuiltGraph::GetPrebuiltGraphFromLibrary(prebuilt_library, engineInterface);
414 }
415
416 } // namespace graph
417 } // namespace computepipe
418 } // namespace automotive
419 } // namespace android
420