blob: d4eaa5ecd58f9374f72282ed3f3056943edd627c [file] [log] [blame]
// 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.
#ifndef COMPUTEPIPE_RUNNER_ENGINE_DEFAULTENGINE_H_
#define COMPUTEPIPE_RUNNER_ENGINE_DEFAULTENGINE_H_
#include <condition_variable>
#include <functional>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#include <vector>
#include "ConfigBuilder.h"
#include "DebugDisplayManager.h"
#include "InputManager.h"
#include "Options.pb.h"
#include "RunnerEngine.h"
#include "StreamManager.h"
namespace android {
namespace automotive {
namespace computepipe {
namespace runner {
namespace engine {
class InputCallback;
/**
* EngineCommand represents client requests or error events.
* Each command is queued, and processed by the engine thread.
*/
struct EngineCommand {
public:
enum Type {
BROADCAST_CONFIG = 0,
BROADCAST_START_RUN,
BROADCAST_INITIATE_STOP,
POLL_COMPLETE,
RESET_CONFIG,
RELEASE_DEBUGGER,
READ_PROFILING,
};
std::string source;
Type cmdType;
explicit EngineCommand(std::string s, Type t) : source(s), cmdType(t) {
}
};
/**
* Component Error represents the type of error reported by a component.
*/
struct ComponentError {
public:
bool isFatal;
std::string source;
std::string message;
std::string currentPhase;
explicit ComponentError(std::string s, std::string m, std::string p, bool fatal = false)
: isFatal(fatal), source(s), message(m), currentPhase(p) {
}
};
/**
* Default Engine implementation.
* Takes ownership of externally instantiated graph & client interface
* instances. Brings the runner online. Manages components.
* Responds to client events.
*/
class DefaultEngine : public RunnerEngine {
public:
static constexpr char kDisplayStreamId[] = "display_stream:";
static constexpr char kNoInputManager[] = "no_input_manager";
static constexpr char kResetPhase[] = "Reset";
static constexpr char kConfigPhase[] = "Config";
static constexpr char kRunPhase[] = "Running";
static constexpr char kStopPhase[] = "Stopping";
/**
* Methods from Runner Engine to override
*/
Status setArgs(std::string engine_args) override;
void setClientInterface(std::unique_ptr<client_interface::ClientInterface>&& client) override;
void setPrebuiltGraph(std::unique_ptr<graph::PrebuiltGraph>&& graph) override;
Status activate() override;
/**
* Methods from ClientEngineInterface to override
*/
Status processClientConfigUpdate(const proto::ConfigurationCommand& command) override;
Status processClientCommand(const proto::ControlCommand& command) override;
Status freePacket(int bufferId, int streamId) override;
/**
* Methods from PrebuiltEngineInterface to override
*/
void DispatchPixelData(int streamId, int64_t timestamp, const InputFrame& frame) override;
void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& output) override;
void DispatchGraphTerminationMessage(Status s, std::string&& msg) override;
private:
// TODO: b/147704051 Add thread analyzer annotations
/**
* BroadCast Client config to all components. If all components handle the
* notification correctly, then broadcast transition complete.
* Successful return from this function implies runner has transitioned to
* configuration done.
* @Lock held mEngineLock
*/
Status broadcastClientConfig();
/**
* Abort an ongoing attempt to apply client configs.
* @Lock held mEngineLock
*/
void abortClientConfig(const ClientConfig& config, bool resetGraph = false);
/**
* BroadCast start to all components. The order of entry into run phase
* notification delivery is downstream components to upstream components.
* If all components handle the entry notification correctly then broadcast
* transition complete notification again from down stream to upstream.
* Successful return from this function implies runner has transitioned to
* running.
* @Lock held mEngineLock
*/
Status broadcastStartRun();
/**
* BroadCast abort of started run to given components. This gets called if during
* broadcastStartRun(), one of the components failed to set itself up for the run. In that case
* the components that had successfully acknowledged broacastStartRun(),
* need to be told to abort. We transition back to config phase at the end
* of this call.
* @Lock held mEngineLock
*/
void broadcastAbortRun(const std::vector<int>& streamIds, const std::vector<int>& inputIds,
bool graph = false);
/**
* Broadcast stop with flush to all components. The stop with flush phase
* entry notification is sent from in the order of upstream to downstream.
* A successful return can leave the runner in stopping phase.
* We transition to stop completely, once all inflight traffic has been drained at a later
* point, identified by stream managers.
* @Lock held mEngineLock
*/
Status broadcastStopWithFlush();
/**
* Broadcast transtion to stop complete. This is a confirmation to all
* components that stop has finished. At the end of this we transition back
* to config phase.
* @Lock held mEngineLock
*/
Status broadcastStopComplete();
/**
* Broadcast halt to all components. All inflight traffic is dropped.
* Successful return from this function implies all components have
* exited run phase and are back in config phase.
* @Lock held mEngineLock
*/
void broadcastHalt();
/**
* Broadcast reset to all components. All components drop client
* specific configuration and transition to reset state. For RAII
* components, they are freed at this point. ALso resets the mConfigBuilder
* to its original state. Successful return puts the runner in reset phase.
* @Lock held mEngineLock
*/
void broadcastReset();
/**
* Populate stream managers for a given client config. For each client
* selected output config, we generate stream managers. During reset phase
* we clear out any previously constructed stream managers. This should be
* invoked only in response to applyConfigs() issued by client.
* @Lock held mEngineLock
*/
Status populateStreamManagers(const ClientConfig& config);
/**
* Populate input managers for a given client config. For each client
* selected output config, we generate input managers. During reset phase
* we clear out any previously constructed input managers. This should be
* invoked only in response to applyConfigs() issued by client.
* @Lock held mEngineLock
*/
Status populateInputManagers(const ClientConfig& config);
/**
* Helper method to forward packet to client interface for transmission
*/
Status forwardOutputDataToClient(int streamId, std::shared_ptr<MemHandle>& handle);
/**
* Helper to handle error notification from components, in the errorQueue.
* In case the source of the error is client interface, it will
* broadcastReset().
* This called in the mEngineThread when processing an entry from the
* errorQueue,
* @Lock acquires mEngineLock.
*/
void processComponentError(std::string source);
/**
* Method run by the engine thread to process commands.
* Uses condition variable. Acquires lock mEngineLock to access
* command queues.
*/
void processCommands();
/**
* Method run by external components to queue commands to the engine.
* Must be called with mEngineLock held. Wakes up the looper.
*/
void queueCommand(std::string source, EngineCommand::Type type);
/**
* Method called by component reporting error.
* This will acquire mEngineLock and queue the error.
*/
void queueError(std::string source, std::string msg, bool fatal);
/**
* client interface handle
*/
std::unique_ptr<client_interface::ClientInterface> mClient = nullptr;
/**
* builder to build up client config incrementally.
*/
ConfigBuilder mConfigBuilder;
/**
* Stream management members
*/
std::map<int, std::unique_ptr<stream_manager::StreamManager>> mStreamManagers;
stream_manager::StreamManagerFactory mStreamFactory;
/**
* Input manager members
*/
std::map<int, std::unique_ptr<input_manager::InputManager>> mInputManagers;
input_manager::InputManagerFactory mInputFactory;
/**
* stream to dump to display for debug purposes
*/
int32_t mDisplayStream = ClientConfig::kInvalidId;
/**
* Debug display manager.
*/
std::unique_ptr<debug_display_manager::DebugDisplayManager> mDebugDisplayManager = nullptr;
/**
* graph descriptor
*/
proto::Options mGraphDescriptor;
std::unique_ptr<graph::PrebuiltGraph> mGraph;
/**
* stop signal source
*/
bool mStopFromClient = true;
/**
* Phase management members
*/
std::string mCurrentPhase = kResetPhase;
std::mutex mEngineLock;
/**
* Used to track the first error occurrence for a given phase.
*/
std::unique_ptr<ComponentError> mCurrentPhaseError = nullptr;
/**
* Queue for client commands
*/
std::queue<EngineCommand> mCommandQueue;
/**
* Queue for error notifications
*/
std::queue<ComponentError> mErrorQueue;
/**
* Engine looper
*/
std::unique_ptr<std::thread> mEngineThread;
/**
* Condition variable for looper
*/
std::condition_variable mWakeLooper;
/**
* ignore input manager allocation
*/
bool mIgnoreInputManager = false;
};
/**
* Handles callbacks from individual stream managers as specified in the
* StreamEngineInterface.
*/
class StreamCallback : public stream_manager::StreamEngineInterface {
public:
explicit StreamCallback(
const std::function<void()>&& eos, const std::function<void(std::string)>&& errorCb,
const std::function<Status(const std::shared_ptr<MemHandle>&)>&& packetHandler);
void notifyEndOfStream() override;
void notifyError(std::string msg) override;
Status dispatchPacket(const std::shared_ptr<MemHandle>& outData) override;
~StreamCallback() = default;
private:
std::function<void(std::string)> mErrorHandler;
std::function<void()> mEndOfStreamHandler;
std::function<Status(const std::shared_ptr<MemHandle>&)> mPacketHandler;
};
/**
* Handles callbacks from input managers. Forwards frames to the graph.
* Only used if graph implementation is local
*/
class InputCallback : public input_manager::InputEngineInterface {
public:
explicit InputCallback(int id, const std::function<void(int)>&& cb,
const std::function<Status(int, int64_t, const InputFrame&)>&& packetCb);
Status dispatchInputFrame(int streamId, int64_t timestamp, const InputFrame& frame) override;
void notifyInputError() override;
~InputCallback() = default;
private:
std::function<void(int)> mErrorCallback;
std::function<Status(int, int64_t, const InputFrame&)> mPacketHandler;
int mInputId;
};
} // namespace engine
} // namespace runner
} // namespace computepipe
} // namespace automotive
} // namespace android
#endif // COMPUTEPIPE_RUNNER_ENGINE_DEFAULTENGINE_H_