You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
420 lines
18 KiB
420 lines
18 KiB
4 months ago
|
// Copyright (C) 2020 The Android Open Source Project
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
#include "LocalPrebuiltGraph.h"
|
||
|
|
||
|
#include <android-base/logging.h>
|
||
|
#include <dlfcn.h>
|
||
|
|
||
|
#include <functional>
|
||
|
#include <iostream>
|
||
|
#include <mutex>
|
||
|
#include <shared_mutex>
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
|
||
|
#include "ClientConfig.pb.h"
|
||
|
#include "InputFrame.h"
|
||
|
#include "PrebuiltGraph.h"
|
||
|
#include "RunnerComponent.h"
|
||
|
#include "prebuilt_interface.h"
|
||
|
#include "types/Status.h"
|
||
|
|
||
|
namespace android {
|
||
|
namespace automotive {
|
||
|
namespace computepipe {
|
||
|
namespace graph {
|
||
|
|
||
|
#define LOAD_FUNCTION(name) \
|
||
|
{ \
|
||
|
std::string func_name = std::string("PrebuiltComputepipeRunner_") + #name; \
|
||
|
mPrebuiltGraphInstance->mFn##name = \
|
||
|
dlsym(mPrebuiltGraphInstance->mHandle, func_name.c_str()); \
|
||
|
if (mPrebuiltGraphInstance->mFn##name == nullptr) { \
|
||
|
initialized = false; \
|
||
|
LOG(ERROR) << std::string(dlerror()) << std::endl; \
|
||
|
} \
|
||
|
}
|
||
|
|
||
|
std::mutex LocalPrebuiltGraph::mCreationMutex;
|
||
|
LocalPrebuiltGraph* LocalPrebuiltGraph::mPrebuiltGraphInstance = nullptr;
|
||
|
|
||
|
// Function to confirm that there would be no further changes to the graph configuration. This
|
||
|
// needs to be called before starting the graph.
|
||
|
Status LocalPrebuiltGraph::handleConfigPhase(const runner::ClientConfig& e) {
|
||
|
if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
|
||
|
return Status::ILLEGAL_STATE;
|
||
|
}
|
||
|
|
||
|
// handleConfigPhase is a blocking call, so abort call is pointless for this RunnerEvent.
|
||
|
if (e.isAborted()) {
|
||
|
return Status::INVALID_ARGUMENT;
|
||
|
} else if (e.isTransitionComplete()) {
|
||
|
return Status::SUCCESS;
|
||
|
}
|
||
|
|
||
|
std::string config = e.getSerializedClientConfig();
|
||
|
auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(const unsigned char*,
|
||
|
size_t))mFnUpdateGraphConfig;
|
||
|
PrebuiltComputepipeRunner_ErrorCode errorCode =
|
||
|
mappedFn(reinterpret_cast<const unsigned char*>(config.c_str()), config.length());
|
||
|
if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
|
||
|
return static_cast<Status>(static_cast<int>(errorCode));
|
||
|
}
|
||
|
|
||
|
// Set the pixel stream callback function. The same function will be called for all requested
|
||
|
// pixel output streams.
|
||
|
if (mEngineInterface.lock() != nullptr) {
|
||
|
auto pixelCallbackFn = (PrebuiltComputepipeRunner_ErrorCode(*)(
|
||
|
void (*)(void* cookie, int, int64_t, const uint8_t* pixels, int width, int height,
|
||
|
int step, int format)))mFnSetOutputPixelStreamCallback;
|
||
|
PrebuiltComputepipeRunner_ErrorCode errorCode =
|
||
|
pixelCallbackFn(LocalPrebuiltGraph::OutputPixelStreamCallbackFunction);
|
||
|
if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
|
||
|
return static_cast<Status>(static_cast<int>(errorCode));
|
||
|
}
|
||
|
|
||
|
// Set the serialized stream callback function. The same callback function will be invoked
|
||
|
// for all requested serialized output streams.
|
||
|
auto streamCallbackFn = (PrebuiltComputepipeRunner_ErrorCode(*)(
|
||
|
void (*)(void* cookie, int, int64_t, const unsigned char*,
|
||
|
size_t)))mFnSetOutputStreamCallback;
|
||
|
errorCode = streamCallbackFn(LocalPrebuiltGraph::OutputStreamCallbackFunction);
|
||
|
if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
|
||
|
return static_cast<Status>(static_cast<int>(errorCode));
|
||
|
}
|
||
|
|
||
|
// Set the callback function for when the graph terminates.
|
||
|
auto terminationCallback = (PrebuiltComputepipeRunner_ErrorCode(*)(
|
||
|
void (*)(void* cookie, const unsigned char*,
|
||
|
size_t)))mFnSetGraphTerminationCallback;
|
||
|
errorCode = terminationCallback(LocalPrebuiltGraph::GraphTerminationCallbackFunction);
|
||
|
if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
|
||
|
return static_cast<Status>(static_cast<int>(errorCode));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Status::SUCCESS;
|
||
|
}
|
||
|
|
||
|
// Starts the graph.
|
||
|
Status LocalPrebuiltGraph::handleExecutionPhase(const runner::RunnerEvent& e) {
|
||
|
if (mGraphState.load() != PrebuiltGraphState::STOPPED) {
|
||
|
return Status::ILLEGAL_STATE;
|
||
|
}
|
||
|
|
||
|
if (e.isAborted()) {
|
||
|
// Starting the graph is a blocking call and cannot be aborted in between.
|
||
|
return Status::INVALID_ARGUMENT;
|
||
|
} else if (e.isTransitionComplete()) {
|
||
|
return Status::SUCCESS;
|
||
|
}
|
||
|
|
||
|
auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(void*))mFnStartGraphExecution;
|
||
|
PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn(reinterpret_cast<void*>(this));
|
||
|
if (errorCode == PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
|
||
|
mGraphState.store(PrebuiltGraphState::RUNNING);
|
||
|
}
|
||
|
return static_cast<Status>(static_cast<int>(errorCode));
|
||
|
}
|
||
|
|
||
|
// Stops the graph while letting the graph flush output packets in flight.
|
||
|
Status LocalPrebuiltGraph::handleStopWithFlushPhase(const runner::RunnerEvent& e) {
|
||
|
if (mGraphState.load() != PrebuiltGraphState::RUNNING) {
|
||
|
return Status::ILLEGAL_STATE;
|
||
|
}
|
||
|
|
||
|
if (e.isAborted()) {
|
||
|
return Status::INVALID_ARGUMENT;
|
||
|
} else if (e.isTransitionComplete()) {
|
||
|
return Status::SUCCESS;
|
||
|
}
|
||
|
|
||
|
return StopGraphExecution(/* flushOutputFrames = */ true);
|
||
|
}
|
||
|
|
||
|
// Stops the graph and cancels all the output packets.
|
||
|
Status LocalPrebuiltGraph::handleStopImmediatePhase(const runner::RunnerEvent& e) {
|
||
|
if (mGraphState.load() != PrebuiltGraphState::RUNNING) {
|
||
|
return Status::ILLEGAL_STATE;
|
||
|
}
|
||
|
|
||
|
if (e.isAborted()) {
|
||
|
return Status::INVALID_ARGUMENT;
|
||
|
} else if (e.isTransitionComplete()) {
|
||
|
return Status::SUCCESS;
|
||
|
}
|
||
|
|
||
|
return StopGraphExecution(/* flushOutputFrames = */ false);
|
||
|
}
|
||
|
|
||
|
Status LocalPrebuiltGraph::handleResetPhase(const runner::RunnerEvent& e) {
|
||
|
if (mGraphState.load() != PrebuiltGraphState::STOPPED) {
|
||
|
return Status::ILLEGAL_STATE;
|
||
|
}
|
||
|
|
||
|
if (e.isAborted()) {
|
||
|
return Status::INVALID_ARGUMENT;
|
||
|
} else if (e.isTransitionComplete()) {
|
||
|
return Status::SUCCESS;
|
||
|
}
|
||
|
|
||
|
auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)())mFnResetGraph;
|
||
|
mappedFn();
|
||
|
return Status::SUCCESS;
|
||
|
}
|
||
|
|
||
|
LocalPrebuiltGraph* LocalPrebuiltGraph::GetPrebuiltGraphFromLibrary(
|
||
|
const std::string& prebuilt_library,
|
||
|
std::weak_ptr<PrebuiltEngineInterface> engineInterface) {
|
||
|
std::unique_lock<std::mutex> lock(LocalPrebuiltGraph::mCreationMutex);
|
||
|
if (mPrebuiltGraphInstance == nullptr) {
|
||
|
mPrebuiltGraphInstance = new LocalPrebuiltGraph();
|
||
|
}
|
||
|
if (mPrebuiltGraphInstance->mGraphState.load() != PrebuiltGraphState::UNINITIALIZED) {
|
||
|
return mPrebuiltGraphInstance;
|
||
|
}
|
||
|
mPrebuiltGraphInstance->mHandle = dlopen(prebuilt_library.c_str(), RTLD_NOW);
|
||
|
|
||
|
if (mPrebuiltGraphInstance->mHandle) {
|
||
|
bool initialized = true;
|
||
|
|
||
|
// Load config and version number first.
|
||
|
const unsigned char* (*getVersionFn)() =
|
||
|
(const unsigned char* (*)())dlsym(mPrebuiltGraphInstance->mHandle,
|
||
|
"PrebuiltComputepipeRunner_GetVersion");
|
||
|
if (getVersionFn != nullptr) {
|
||
|
mPrebuiltGraphInstance->mGraphVersion =
|
||
|
std::string(reinterpret_cast<const char*>(getVersionFn()));
|
||
|
} else {
|
||
|
LOG(ERROR) << std::string(dlerror());
|
||
|
initialized = false;
|
||
|
}
|
||
|
|
||
|
void (*getSupportedGraphConfigsFn)(const void**, size_t*) =
|
||
|
(void (*)(const void**,
|
||
|
size_t*))dlsym(mPrebuiltGraphInstance->mHandle,
|
||
|
"PrebuiltComputepipeRunner_GetSupportedGraphConfigs");
|
||
|
if (getSupportedGraphConfigsFn != nullptr) {
|
||
|
size_t graphConfigSize;
|
||
|
const void* graphConfig;
|
||
|
|
||
|
getSupportedGraphConfigsFn(&graphConfig, &graphConfigSize);
|
||
|
|
||
|
if (graphConfigSize > 0) {
|
||
|
initialized &= mPrebuiltGraphInstance->mGraphConfig.ParseFromString(
|
||
|
std::string(reinterpret_cast<const char*>(graphConfig), graphConfigSize));
|
||
|
}
|
||
|
} else {
|
||
|
LOG(ERROR) << std::string(dlerror());
|
||
|
initialized = false;
|
||
|
}
|
||
|
|
||
|
// Null callback interface is not acceptable.
|
||
|
if (initialized && engineInterface.lock() == nullptr) {
|
||
|
initialized = false;
|
||
|
}
|
||
|
|
||
|
LOAD_FUNCTION(GetErrorCode);
|
||
|
LOAD_FUNCTION(GetErrorMessage);
|
||
|
LOAD_FUNCTION(ResetGraph);
|
||
|
LOAD_FUNCTION(UpdateGraphConfig);
|
||
|
LOAD_FUNCTION(SetInputStreamData);
|
||
|
LOAD_FUNCTION(SetInputStreamPixelData);
|
||
|
LOAD_FUNCTION(SetOutputStreamCallback);
|
||
|
LOAD_FUNCTION(SetOutputPixelStreamCallback);
|
||
|
LOAD_FUNCTION(SetGraphTerminationCallback);
|
||
|
LOAD_FUNCTION(StartGraphExecution);
|
||
|
LOAD_FUNCTION(StopGraphExecution);
|
||
|
LOAD_FUNCTION(StartGraphProfiling);
|
||
|
LOAD_FUNCTION(StopGraphProfiling);
|
||
|
LOAD_FUNCTION(GetDebugInfo);
|
||
|
|
||
|
// This is the only way to create this object and there is already a
|
||
|
// lock around object creation, so no need to hold the graphState lock
|
||
|
// here.
|
||
|
if (initialized) {
|
||
|
mPrebuiltGraphInstance->mGraphState.store(PrebuiltGraphState::STOPPED);
|
||
|
mPrebuiltGraphInstance->mEngineInterface = engineInterface;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return mPrebuiltGraphInstance;
|
||
|
}
|
||
|
|
||
|
LocalPrebuiltGraph::~LocalPrebuiltGraph() {
|
||
|
if (mHandle) {
|
||
|
dlclose(mHandle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Status LocalPrebuiltGraph::GetStatus() const {
|
||
|
if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
|
||
|
return Status::ILLEGAL_STATE;
|
||
|
}
|
||
|
|
||
|
auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)())mFnGetErrorCode;
|
||
|
PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn();
|
||
|
return static_cast<Status>(static_cast<int>(errorCode));
|
||
|
}
|
||
|
|
||
|
std::string LocalPrebuiltGraph::GetErrorMessage() const {
|
||
|
if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
|
||
|
return "Graph has not been initialized";
|
||
|
}
|
||
|
auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(unsigned char*, size_t,
|
||
|
size_t*))mFnGetErrorMessage;
|
||
|
size_t errorMessageSize = 0;
|
||
|
|
||
|
PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn(nullptr, 0, &errorMessageSize);
|
||
|
std::vector<unsigned char> errorMessage(errorMessageSize);
|
||
|
|
||
|
errorCode = mappedFn(&errorMessage[0], errorMessage.size(), &errorMessageSize);
|
||
|
if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
|
||
|
return "Unable to get error message from the graph.";
|
||
|
}
|
||
|
|
||
|
return std::string(reinterpret_cast<char*>(&errorMessage[0]),
|
||
|
reinterpret_cast<char*>(&errorMessage[0]) + errorMessage.size());
|
||
|
}
|
||
|
|
||
|
Status LocalPrebuiltGraph::SetInputStreamData(int streamIndex, int64_t timestamp,
|
||
|
const std::string& streamData) {
|
||
|
if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
|
||
|
return Status::ILLEGAL_STATE;
|
||
|
}
|
||
|
auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(int, int64_t, const unsigned char*,
|
||
|
size_t))mFnSetInputStreamData;
|
||
|
PrebuiltComputepipeRunner_ErrorCode errorCode =
|
||
|
mappedFn(streamIndex, timestamp,
|
||
|
reinterpret_cast<const unsigned char*>(streamData.c_str()),
|
||
|
streamData.length());
|
||
|
return static_cast<Status>(static_cast<int>(errorCode));
|
||
|
}
|
||
|
|
||
|
Status LocalPrebuiltGraph::SetInputStreamPixelData(int streamIndex, int64_t timestamp,
|
||
|
const runner::InputFrame& inputFrame) {
|
||
|
if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
|
||
|
return Status::ILLEGAL_STATE;
|
||
|
}
|
||
|
|
||
|
auto mappedFn =
|
||
|
(PrebuiltComputepipeRunner_ErrorCode(*)(int, int64_t, const uint8_t*, int, int, int,
|
||
|
PrebuiltComputepipeRunner_PixelDataFormat))
|
||
|
mFnSetInputStreamPixelData;
|
||
|
PrebuiltComputepipeRunner_ErrorCode errorCode =
|
||
|
mappedFn(streamIndex, timestamp, inputFrame.getFramePtr(),
|
||
|
inputFrame.getFrameInfo().width, inputFrame.getFrameInfo().height,
|
||
|
inputFrame.getFrameInfo().stride,
|
||
|
static_cast<PrebuiltComputepipeRunner_PixelDataFormat>(
|
||
|
static_cast<int>(inputFrame.getFrameInfo().format)));
|
||
|
return static_cast<Status>(static_cast<int>(errorCode));
|
||
|
}
|
||
|
|
||
|
Status LocalPrebuiltGraph::StopGraphExecution(bool flushOutputFrames) {
|
||
|
auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(bool))mFnStopGraphExecution;
|
||
|
PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn(flushOutputFrames);
|
||
|
if (errorCode == PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
|
||
|
mGraphState.store(flushOutputFrames ? PrebuiltGraphState::FLUSHING
|
||
|
: PrebuiltGraphState::STOPPED);
|
||
|
}
|
||
|
return static_cast<Status>(static_cast<int>(errorCode));
|
||
|
}
|
||
|
|
||
|
Status LocalPrebuiltGraph::StartGraphProfiling() {
|
||
|
auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)())mFnStartGraphProfiling;
|
||
|
PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn();
|
||
|
return static_cast<Status>(static_cast<int>(errorCode));
|
||
|
}
|
||
|
|
||
|
Status LocalPrebuiltGraph::StopGraphProfiling() {
|
||
|
auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)())mFnStopGraphProfiling;
|
||
|
PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn();
|
||
|
return static_cast<Status>(static_cast<int>(errorCode));
|
||
|
}
|
||
|
|
||
|
std::string LocalPrebuiltGraph::GetDebugInfo() {
|
||
|
if (mGraphState.load() == PrebuiltGraphState::UNINITIALIZED) {
|
||
|
return "";
|
||
|
}
|
||
|
auto mappedFn = (PrebuiltComputepipeRunner_ErrorCode(*)(unsigned char*, size_t,
|
||
|
size_t*))mFnGetDebugInfo;
|
||
|
|
||
|
size_t debugInfoSize = 0;
|
||
|
PrebuiltComputepipeRunner_ErrorCode errorCode = mappedFn(nullptr, 0, &debugInfoSize);
|
||
|
std::vector<unsigned char> debugInfo(debugInfoSize);
|
||
|
|
||
|
errorCode = mappedFn(&debugInfo[0], debugInfo.size(), &debugInfoSize);
|
||
|
if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
return std::string(reinterpret_cast<char*>(&debugInfo[0]),
|
||
|
reinterpret_cast<char*>(&debugInfo[0]) + debugInfo.size());
|
||
|
}
|
||
|
|
||
|
void LocalPrebuiltGraph::OutputStreamCallbackFunction(void* cookie, int streamIndex,
|
||
|
int64_t timestamp, const unsigned char* data,
|
||
|
size_t data_size) {
|
||
|
LocalPrebuiltGraph* graph = reinterpret_cast<LocalPrebuiltGraph*>(cookie);
|
||
|
CHECK(graph);
|
||
|
std::shared_ptr<PrebuiltEngineInterface> engineInterface = graph->mEngineInterface.lock();
|
||
|
if (engineInterface != nullptr) {
|
||
|
engineInterface->DispatchSerializedData(streamIndex, timestamp,
|
||
|
std::string(data, data + data_size));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void LocalPrebuiltGraph::OutputPixelStreamCallbackFunction(void* cookie, int streamIndex,
|
||
|
int64_t timestamp, const uint8_t* pixels,
|
||
|
int width, int height, int step,
|
||
|
int format) {
|
||
|
LocalPrebuiltGraph* graph = reinterpret_cast<LocalPrebuiltGraph*>(cookie);
|
||
|
CHECK(graph);
|
||
|
std::shared_ptr<PrebuiltEngineInterface> engineInterface = graph->mEngineInterface.lock();
|
||
|
|
||
|
if (engineInterface) {
|
||
|
runner::InputFrame frame(height, width, static_cast<PixelFormat>(format), step, pixels);
|
||
|
engineInterface->DispatchPixelData(streamIndex, timestamp, frame);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void LocalPrebuiltGraph::GraphTerminationCallbackFunction(void* cookie,
|
||
|
const unsigned char* termination_message,
|
||
|
size_t termination_message_size) {
|
||
|
LocalPrebuiltGraph* graph = reinterpret_cast<LocalPrebuiltGraph*>(cookie);
|
||
|
CHECK(graph);
|
||
|
std::shared_ptr<PrebuiltEngineInterface> engineInterface = graph->mEngineInterface.lock();
|
||
|
|
||
|
if (engineInterface) {
|
||
|
std::string errorMessage = "";
|
||
|
if (termination_message != nullptr && termination_message_size > 0) {
|
||
|
std::string(termination_message, termination_message + termination_message_size);
|
||
|
}
|
||
|
graph->mGraphState.store(PrebuiltGraphState::STOPPED);
|
||
|
engineInterface->DispatchGraphTerminationMessage(graph->GetStatus(),
|
||
|
std::move(errorMessage));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PrebuiltGraph* GetLocalGraphFromLibrary(const std::string& prebuilt_library,
|
||
|
std::weak_ptr<PrebuiltEngineInterface> engineInterface) {
|
||
|
return LocalPrebuiltGraph::GetPrebuiltGraphFromLibrary(prebuilt_library, engineInterface);
|
||
|
}
|
||
|
|
||
|
} // namespace graph
|
||
|
} // namespace computepipe
|
||
|
} // namespace automotive
|
||
|
} // namespace android
|