Adding the interface file for the prebuilt computepipe graph execution
library.
Android runner will use this c interface to interact with the prebuilt
graph execution library.
Change-Id: Ifa974c7a1e4b8859ebac7eff1ff8520e365a4319
Fix: 146518209, 146518511, 145230095
Test: Unit tests added to verify function calls into the prebuilt.
diff --git a/computepipe/runner/graph/Android.bp b/computepipe/runner/graph/Android.bp
new file mode 100644
index 0000000..589c00f
--- /dev/null
+++ b/computepipe/runner/graph/Android.bp
@@ -0,0 +1,48 @@
+// Copyright (C) 2019 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.
+
+cc_library {
+ name: "computepipe_prebuilt_graph",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wno-unused-parameter",
+ ],
+
+ export_include_dirs: ["include"],
+ static_libs: [
+ "computepipe_runner_component",
+ "libcomputepipeprotos",
+ ],
+
+ header_libs: ["computepipe_runner_includes"],
+ include_dirs: [
+ "packages/services/Car/computepipe",
+ "packages/services/Car/computepipe/runner/graph",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libdl",
+ "liblog",
+ "libutils",
+ "libprotobuf-cpp-lite",
+ ],
+
+ srcs: [
+ "PrebuiltGraph.cpp",
+ ],
+}
diff --git a/computepipe/runner/graph/PrebuiltGraph.cpp b/computepipe/runner/graph/PrebuiltGraph.cpp
new file mode 100644
index 0000000..eef3113
--- /dev/null
+++ b/computepipe/runner/graph/PrebuiltGraph.cpp
@@ -0,0 +1,369 @@
+// 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 "PrebuiltGraph.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 "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 PrebuiltGraph::mCreationMutex;
+PrebuiltGraph* PrebuiltGraph::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 PrebuiltGraph::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) {
+ 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(PrebuiltGraph::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(PrebuiltGraph::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(PrebuiltGraph::GraphTerminationCallbackFunction);
+ if (errorCode != PrebuiltComputepipeRunner_ErrorCode::SUCCESS) {
+ return static_cast<Status>(static_cast<int>(errorCode));
+ }
+ }
+
+ return Status::SUCCESS;
+}
+
+// Starts the graph.
+Status PrebuiltGraph::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*, bool))mFnStartGraphExecution;
+ PrebuiltComputepipeRunner_ErrorCode errorCode =
+ mappedFn(reinterpret_cast<void*>(this), /* debuggingEnabled =*/false);
+ 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 PrebuiltGraph::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 PrebuiltGraph::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 PrebuiltGraph::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;
+}
+
+PrebuiltGraph* PrebuiltGraph::GetPrebuiltGraphFromLibrary(
+ const std::string& prebuilt_library, std::shared_ptr<PrebuiltEngineInterface> engineInterface) {
+ std::unique_lock<std::mutex> lock(PrebuiltGraph::mCreationMutex);
+ if (mPrebuiltGraphInstance != nullptr) {
+ mPrebuiltGraphInstance = new PrebuiltGraph();
+ }
+ 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;
+ }
+
+ const unsigned char* (*getSupportedGraphConfigsFn)() = (const unsigned char* (*)())dlsym(
+ mPrebuiltGraphInstance->mHandle, "PrebuiltComputepipeRunner_GetSupportedGraphConfigs");
+ if (getSupportedGraphConfigsFn != nullptr) {
+ initialized &= mPrebuiltGraphInstance->mGraphConfig.ParseFromString(
+ std::string(reinterpret_cast<const char*>(getSupportedGraphConfigsFn())));
+ } else {
+ LOG(ERROR) << std::string(dlerror());
+ initialized = false;
+ }
+
+ // Null callback interface is not acceptable.
+ if (initialized && engineInterface == 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(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;
+}
+
+PrebuiltGraph::~PrebuiltGraph() {
+ if (mHandle) {
+ dlclose(mHandle);
+ }
+}
+
+Status PrebuiltGraph::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 PrebuiltGraph::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 PrebuiltGraph::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 PrebuiltGraph::SetInputStreamPixelData(int streamIndex, int64_t timestamp,
+ const uint8_t* pixels, int width, int height,
+ int step, PixelFormat format) {
+ 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, pixels, width, height, step,
+ static_cast<PrebuiltComputepipeRunner_PixelDataFormat>(static_cast<int>(format)));
+ return static_cast<Status>(static_cast<int>(errorCode));
+}
+
+Status PrebuiltGraph::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));
+}
+
+std::string PrebuiltGraph::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 PrebuiltGraph::OutputStreamCallbackFunction(void* cookie, int streamIndex, int64_t timestamp,
+ const unsigned char* data, size_t data_size) {
+ PrebuiltGraph* graph = reinterpret_cast<PrebuiltGraph*>(cookie);
+ CHECK(graph);
+ graph->mEngineInterface->DispatchSerializedData(streamIndex, timestamp,
+ std::string(data, data + data_size));
+}
+
+void PrebuiltGraph::OutputPixelStreamCallbackFunction(void* cookie, int streamIndex,
+ int64_t timestamp, const uint8_t* pixels,
+ int width, int height, int step, int format) {
+ PrebuiltGraph* graph = reinterpret_cast<PrebuiltGraph*>(cookie);
+ CHECK(graph);
+ graph->mEngineInterface->DispatchPixelData(streamIndex, timestamp, pixels, width, height, step,
+ static_cast<PixelFormat>(format));
+}
+
+void PrebuiltGraph::GraphTerminationCallbackFunction(void* cookie,
+ const unsigned char* termination_message,
+ size_t termination_message_size) {
+ PrebuiltGraph* graph = reinterpret_cast<PrebuiltGraph*>(cookie);
+ CHECK(graph);
+ 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);
+ graph->mEngineInterface->DispatchGraphTerminationMessage(graph->GetStatus(),
+ std::move(errorMessage));
+}
+
+} // namespace graph
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
diff --git a/computepipe/runner/graph/include/PrebuiltEngineInterface.h b/computepipe/runner/graph/include/PrebuiltEngineInterface.h
new file mode 100644
index 0000000..197ef8b
--- /dev/null
+++ b/computepipe/runner/graph/include/PrebuiltEngineInterface.h
@@ -0,0 +1,43 @@
+// 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_GRAPH_INCLUDE_PREBUILTENGINEINTERFACE_H_
+#define COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_PREBUILTENGINEINTERFACE_H_
+
+#include <functional>
+
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+class PrebuiltEngineInterface {
+ public:
+ virtual ~PrebuiltEngineInterface() = default;
+
+ virtual void DispatchPixelData(int streamId, int64_t timestamp, const uint8_t* pixels,
+ int width, int height, int step, PixelFormat format) = 0;
+
+ virtual void DispatchSerializedData(int streamId, int64_t timestamp, std::string&&) = 0;
+
+ virtual void DispatchGraphTerminationMessage(Status, std::string&&) = 0;
+};
+
+} // namespace graph
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
+
+#endif // COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_PREBUILTENGINEINTERFACE_H_
diff --git a/computepipe/runner/graph/include/PrebuiltGraph.h b/computepipe/runner/graph/include/PrebuiltGraph.h
new file mode 100644
index 0000000..f96a8ad
--- /dev/null
+++ b/computepipe/runner/graph/include/PrebuiltGraph.h
@@ -0,0 +1,152 @@
+// 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_GRAPH_INCLUDE_PREBUILTGRAPH_H_
+#define COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_PREBUILTGRAPH_H_
+
+#include <functional>
+#include <shared_mutex>
+#include <string>
+
+#include "ClientConfig.pb.h"
+#include "Options.pb.h"
+#include "PrebuiltEngineInterface.h"
+#include "RunnerComponent.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+enum PrebuiltGraphState {
+ RUNNING = 0,
+ UNINITIALIZED,
+ FLUSHING,
+ STOPPED,
+};
+
+// PrebuiltGraph is a singleton class. This is because the underlying functions that it implements
+// are C functions that carry around state.
+class PrebuiltGraph : public runner::RunnerComponentInterface {
+ private:
+ // Private constructor
+ PrebuiltGraph() {
+ }
+
+ public:
+ ~PrebuiltGraph();
+
+ // No copy or move constructors or operators are available.
+ PrebuiltGraph(const PrebuiltGraph&) = delete;
+ PrebuiltGraph& operator=(const PrebuiltGraph&) = delete;
+ PrebuiltGraph(PrebuiltGraph&&) = delete;
+ PrebuiltGraph& operator=(PrebuiltGraph&&) = delete;
+
+ // Override RunnerComponent interface functions for applying configs,
+ // starting the graph and stopping the graph.
+ Status handleConfigPhase(const runner::ClientConfig& e) override;
+ Status handleExecutionPhase(const runner::RunnerEvent& e) override;
+ Status handleStopWithFlushPhase(const runner::RunnerEvent& e) override;
+ Status handleStopImmediatePhase(const runner::RunnerEvent& e) override;
+ Status handleResetPhase(const runner::RunnerEvent& e) override;
+
+ static PrebuiltGraph* GetPrebuiltGraphFromLibrary(
+ const std::string& prebuiltLib, std::shared_ptr<PrebuiltEngineInterface> engineInterface);
+
+ PrebuiltGraphState GetGraphState() const {
+ return mGraphState;
+ }
+
+ Status GetStatus() const;
+
+ std::string GetErrorMessage() const;
+
+ // Gets the supported graph config options.
+ const proto::Options& GetSupportedGraphConfigs() const {
+ return mGraphConfig;
+ }
+
+ // Sets input stream data. The string is expected to be a serialized proto
+ // the definition of which is known to the graph.
+ Status SetInputStreamData(int streamIndex, int64_t timestamp, const std::string& streamData);
+
+ // Sets pixel data to the specified input stream index.
+ Status SetInputStreamPixelData(int streamIndex, int64_t timestamp, const uint8_t* pixels,
+ int width, int height, int step, PixelFormat format);
+
+ // Collects debugging and profiling information for the graph. The graph
+ // needs to be started with debugging enabled in order to get valid info.
+ std::string GetDebugInfo();
+
+ private:
+ // Starts the graph execution.
+ Status StartGraphExecution(bool debuggingEnabled);
+
+ // Stops the graph execution.
+ Status StopGraphExecution(bool flushOutputFrames);
+
+ // Callback functions. The class has a C++ function callback interface while it deals with pure
+ // C functions underneath that do not have object context. We need to have these static
+ // functions that need to be passed to the C interface.
+ static void OutputPixelStreamCallbackFunction(void* cookie, int streamIndex, int64_t timestamp,
+ const uint8_t* pixels, int width, int height,
+ int step, int format);
+ static void OutputStreamCallbackFunction(void* cookie, int streamIndex, int64_t timestamp,
+ const unsigned char* data, size_t dataSize);
+ static void GraphTerminationCallbackFunction(void* cookie,
+ const unsigned char* terminationMessage,
+ size_t terminationMessageSize);
+
+ // Cached callback interface that is passed in from the runner.
+ std::shared_ptr<PrebuiltEngineInterface> mEngineInterface;
+
+ static std::mutex mCreationMutex;
+ static PrebuiltGraph* mPrebuiltGraphInstance;
+
+ // Even though mutexes are generally preferred over atomics, the only varialble in this class
+ // that changes after initialization is graph state and that is the only vairable that needs
+ // to be guarded. The prebuilt is internally assumed to be thread safe, so that concurrent
+ // calls into the library will automatically be handled in a thread safe manner by the it.
+ std::atomic<PrebuiltGraphState> mGraphState = PrebuiltGraphState::UNINITIALIZED;
+
+ // Dynamic library handle
+ void* mHandle;
+
+ // Repeated function calls need not be made to get the graph version and the config is this is
+ // constant through the operation of the graph. These values are just cached as strings.
+ std::string mGraphVersion;
+ proto::Options mGraphConfig;
+
+ // Cached functions from the dynamic library.
+ void* mFnGetErrorCode;
+ void* mFnGetErrorMessage;
+ void* mFnUpdateGraphConfig;
+ void* mFnResetGraph;
+ void* mFnSetInputStreamData;
+ void* mFnSetInputStreamPixelData;
+ void* mFnSetOutputStreamCallback;
+ void* mFnSetOutputPixelStreamCallback;
+ void* mFnSetGraphTerminationCallback;
+ void* mFnStartGraphExecution;
+ void* mFnStopGraphExecution;
+ void* mFnGetDebugInfo;
+};
+
+} // namespace graph
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
+
+#endif // COMPUTEPIPE_RUNNER_GRAPH_INCLUDE_PREBUILTGRAPH_H_
diff --git a/computepipe/runner/include/prebuilt_interface.h b/computepipe/runner/include/prebuilt_interface.h
new file mode 100644
index 0000000..0210775
--- /dev/null
+++ b/computepipe/runner/include/prebuilt_interface.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2019 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_INCLUDE_PREBUILT_INTERFACE_H_
+#define COMPUTEPIPE_RUNNER_INCLUDE_PREBUILT_INTERFACE_H_
+
+#include <cstddef>
+#include <cstdint>
+
+#define COMPUTEPIPE_RUNNER(a) PrebuiltComputepipeRunner_##a
+
+extern "C" {
+
+// Enum value to report the error code for function calls.
+enum PrebuiltComputepipeRunner_ErrorCode {
+ SUCCESS = 0,
+ INTERNAL_ERROR,
+ INVALID_ARGUMENT,
+ ILLEGAL_STATE,
+ NO_MEMORY,
+ FATAL_ERROR,
+ ERROR_CODE_MAX,
+};
+
+enum PrebuiltComputepipeRunner_PixelDataFormat {
+ RGB = 0,
+ RGBA = 1,
+ GRAY = 2,
+ PIXEL_DATA_FORMAT_MAX = 3,
+};
+
+// Gets the version of the library. The runner should check if the version of
+// the prebuilt matches the version of android runner for which it was built
+// and fail out if needed.
+const unsigned char* COMPUTEPIPE_RUNNER(GetVersion)();
+
+// Gets the error code. This API is necessary because the graph execution is
+// asynchronous and even if the function calls to execute the graph succeed, it
+// could fail at a later point in the execution of the graph.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(GetErrorCode)();
+
+// Gets the graph error message from the graph. The return value is not the
+// graph error code but the error code returned if the call to the function
+// fails.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(GetErrorMessage)(
+ unsigned char* error_msg_buffer, size_t error_msg_buffer_size, size_t* error_msg_size);
+
+// Gets the supported graph config options.
+const unsigned char* COMPUTEPIPE_RUNNER(GetSupportedGraphConfigs)();
+
+// Sets the graph configuration or updates it if an incomplete config is passed.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(UpdateGraphConfig)(
+ const unsigned char* graph_config, size_t graph_config_size);
+
+// Sets the stream contents. This can only be used after the graph has started
+// running successfully. The contents of this stream are typically a serialized
+// proto and would be deserialized and fed into the graph.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(SetInputStreamData)(
+ int stream_index, int64_t timestamp, const unsigned char* stream_data, size_t stream_data_size);
+
+// Sets the pixel data as stream contents. This can be set only after the graph
+// has started running successfully. Pixel data should be copied within this
+// function as there are no guarantess on the lifetime of the pixel data beyond
+// the return of this function call.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(SetInputStreamPixelData)(
+ int stream_index, int64_t timestamp, const uint8_t* pixels, int width, int height, int step,
+ int format);
+
+// Sets a callback function for when a packet is generated. Note that a c-style
+// function needs to be passed as no object context is being passed around here.
+// The runner would be responsible for using the buffer provided in the callback
+// immediately or copying it as there are no guarantees on its lifetime beyond
+// the return of the callback.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(SetOutputStreamCallback)(
+ void (*streamCallback)(void* cookie, int stream_index, int64_t timestamp,
+ const unsigned char* data, size_t data_size));
+
+// Sets a callback function for when new pixel data is generated. C-style
+// function pointers need to passed as no object context is being passed around.
+// The runner would be responsible for immediately copying out the data. The
+// prebuilt is expected to pass contiguous data.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(SetOutputPixelStreamCallback)(
+ void (*streamCallback)(void* cookie, int stream_index, int64_t timestamp, const uint8_t* pixels,
+ int width, int height, int step, int format));
+
+// Sets a callback function for when the graph terminates.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(SetGraphTerminationCallback)(
+ void (*terminationCallback)(void* cookie, const unsigned char* termination_message,
+ size_t termination_message_size));
+
+// Starts the graph execution. Debugging can be enabled which will enable
+// profiling. The profiling info can be obtained by calling getDebugInfo once
+// the graph execution has stopped.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(StartGraphExecution)(void* cookie,
+ bool debugging_enabled);
+
+// Stops the graph execution.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(StopGraphExecution)(bool flushOutputFrames);
+
+// Resets the graph completely. Should be called only after graph execution has been stopped.
+void COMPUTEPIPE_RUNNER(ResetGraph)();
+
+// Get debugging/profiling information. The function outputs the size of
+// profiling information string and if the buffer size is larger than or equal
+// to the size, then it copies it over to the buffer. Debugging info will be
+// empty if the graph is started without debugging support.
+PrebuiltComputepipeRunner_ErrorCode COMPUTEPIPE_RUNNER(GetDebugInfo)(unsigned char* debug_info,
+ size_t debug_info_buffer_size,
+ size_t* debug_info_size);
+}
+#endif // COMPUTEPIPE_RUNNER_INCLUDE_PREBUILT_INTERFACE_H_
diff --git a/computepipe/tests/runner/Android.bp b/computepipe/tests/runner/Android.bp
index a3edb37..144f42b 100644
--- a/computepipe/tests/runner/Android.bp
+++ b/computepipe/tests/runner/Android.bp
@@ -21,7 +21,7 @@
static_libs: [
"libgtest",
"libgmock",
- "libcomputepipeprotos",
+ "libcomputepipeprotos",
],
shared_libs: [
"libcomputepipe_stream_manager",
diff --git a/computepipe/tests/runner/graph/Android.bp b/computepipe/tests/runner/graph/Android.bp
new file mode 100644
index 0000000..e8aad96
--- /dev/null
+++ b/computepipe/tests/runner/graph/Android.bp
@@ -0,0 +1,44 @@
+// 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.
+
+cc_test {
+ name: "computepipe_prebuilt_graph_test",
+ test_suites: ["device-tests"],
+ srcs: [
+ "EnumConversionTest.cpp",
+ "PrebuiltGraphTest.cpp",
+ ],
+ static_libs: [
+ "computepipe_prebuilt_graph",
+ "computepipe_runner_component",
+ "libgtest",
+ "libgmock",
+ "libcomputepipeprotos",
+ ],
+ shared_libs: [
+ "libstubgraphimpl",
+ "libprotobuf-cpp-full",
+ "liblog",
+ "libdl",
+ "libbase",
+ ],
+ header_libs: [
+ "computepipe_runner_includes",
+ ],
+ include_dirs: [
+ "packages/services/Car/computepipe",
+ "packages/services/Car/computepipe/runner/graph",
+ ],
+
+}
diff --git a/computepipe/tests/runner/graph/EnumConversionTest.cpp b/computepipe/tests/runner/graph/EnumConversionTest.cpp
new file mode 100644
index 0000000..bbb9408
--- /dev/null
+++ b/computepipe/tests/runner/graph/EnumConversionTest.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright 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 "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "prebuilt_interface.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+namespace {
+
+TEST(EnumConversionTest, StatusToErrorCodeEnums) {
+ EXPECT_EQ(static_cast<int>(PrebuiltComputepipeRunner_ErrorCode::SUCCESS),
+ static_cast<int>(Status::SUCCESS));
+ EXPECT_EQ(static_cast<int>(PrebuiltComputepipeRunner_ErrorCode::INTERNAL_ERROR),
+ static_cast<int>(Status::INTERNAL_ERROR));
+ EXPECT_EQ(PrebuiltComputepipeRunner_ErrorCode::INVALID_ARGUMENT,
+ static_cast<int>(Status::INVALID_ARGUMENT));
+ EXPECT_EQ(PrebuiltComputepipeRunner_ErrorCode::ILLEGAL_STATE,
+ static_cast<int>(Status::ILLEGAL_STATE));
+ EXPECT_EQ(PrebuiltComputepipeRunner_ErrorCode::NO_MEMORY, static_cast<int>(Status::NO_MEMORY));
+ EXPECT_EQ(PrebuiltComputepipeRunner_ErrorCode::FATAL_ERROR,
+ static_cast<int>(Status::FATAL_ERROR));
+ EXPECT_EQ(PrebuiltComputepipeRunner_ErrorCode::ERROR_CODE_MAX,
+ static_cast<int>(Status::STATUS_MAX));
+}
+enum PrebuiltComputepipeRunner_PixelDataFormat {
+ RGB = 0,
+ RGBA = 1,
+ GRAY = 2,
+ PIXEL_DATA_FORMAT_MAX = 3,
+};
+TEST(EnumConversionTest, PixelFormatEnums) {
+ EXPECT_EQ(static_cast<int>(PrebuiltComputepipeRunner_PixelDataFormat::RGB),
+ static_cast<int>(PixelFormat::RGB));
+ EXPECT_EQ(static_cast<int>(PrebuiltComputepipeRunner_PixelDataFormat::RGBA),
+ static_cast<int>(PixelFormat::RGBA));
+ EXPECT_EQ(PrebuiltComputepipeRunner_PixelDataFormat::GRAY, static_cast<int>(PixelFormat::GRAY));
+ EXPECT_EQ(PrebuiltComputepipeRunner_PixelDataFormat::PIXEL_DATA_FORMAT_MAX,
+ static_cast<int>(PixelFormat::PIXELFORMAT_MAX));
+}
+
+} // namespace
+} // namespace graph
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
diff --git a/computepipe/tests/runner/graph/PrebuiltGraphTest.cpp b/computepipe/tests/runner/graph/PrebuiltGraphTest.cpp
new file mode 100644
index 0000000..6a77b7e
--- /dev/null
+++ b/computepipe/tests/runner/graph/PrebuiltGraphTest.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright 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 <string>
+
+#include "ClientConfig.pb.h"
+#include "PrebuiltEngineInterface.h"
+#include "PrebuiltGraph.h"
+#include "RunnerComponent.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "types/Status.h"
+
+using ::android::automotive::computepipe::runner::ClientConfig;
+using ::android::automotive::computepipe::runner::RunnerComponentInterface;
+using ::android::automotive::computepipe::runner::RunnerEvent;
+using ::testing::HasSubstr;
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+namespace {
+
+// Barebones implementation of the PrebuiltEngineInterface. This implementation should suffice for
+// basic cases. More complicated use cases might need their own implementation of it.
+typedef std::function<void(int, int64_t, const uint8_t*, int, int, int, PixelFormat)> PixelCallback;
+typedef std::function<void(int, int64_t, std::string&&)> SerializedStreamCallback;
+typedef std::function<void(Status, std::string&&)> GraphTerminationCallback;
+class PrebuiltEngineInterfaceImpl : public PrebuiltEngineInterface {
+ private:
+ PixelCallback mPixelCallbackFn;
+ SerializedStreamCallback mSerializedStreamCallbackFn;
+ GraphTerminationCallback mGraphTerminationCallbackFn;
+
+ public:
+ virtual ~PrebuiltEngineInterfaceImpl() = default;
+
+ void DispatchPixelData(int streamId, int64_t timestamp, const uint8_t* pixels, int width,
+ int height, int step, PixelFormat format) override {
+ mPixelCallbackFn(streamId, timestamp, pixels, width, height, step, format);
+ }
+
+ void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& data) override {
+ mSerializedStreamCallbackFn(streamId, timestamp, std::move(data));
+ }
+
+ void DispatchGraphTerminationMessage(Status status, std::string&& msg) override {
+ mGraphTerminationCallbackFn(status, std::move(msg));
+ }
+
+ void SetPixelCallback(PixelCallback callback) {
+ mPixelCallbackFn = callback;
+ }
+
+ void SetSerializedStreamCallback(SerializedStreamCallback callback) {
+ mSerializedStreamCallbackFn = callback;
+ }
+
+ void SetGraphTerminationCallback(GraphTerminationCallback callback) {
+ mGraphTerminationCallbackFn = callback;
+ }
+};
+
+// The stub graph implementation is a passthrough implementation that does not run
+// any graph and returns success for all implementations. The only useful things that
+// it does for the tests are
+//
+// 1. Stores the name of the function last visited and returns that with GetErrorMessage call
+// 2. When an input stream is set, it immediately returns an output callback with the same input
+// data and timestamp. Similar callback is issued for when input stream pixel data is set too
+//
+// The above two properties are used to test that the prebuilt graph wrapper calls the correct
+// functions and callbacks are issued as expected. These tests do not test the internals of the
+// graph themselves and such tests must be written along with the graph implementation.
+TEST(PrebuiltGraphTest, FunctionMappingFromLibraryIsSuccessful) {
+ PrebuiltEngineInterfaceImpl callback;
+ std::shared_ptr<PrebuiltEngineInterface> engineInterface =
+ std::static_pointer_cast<PrebuiltEngineInterface, PrebuiltEngineInterfaceImpl>(
+ std::make_shared<PrebuiltEngineInterfaceImpl>(callback));
+ PrebuiltGraph* graph =
+ PrebuiltGraph::GetPrebuiltGraphFromLibrary("libstubgraphimpl.so", engineInterface);
+ ASSERT_TRUE(graph);
+ EXPECT_NE(graph->GetGraphState(), PrebuiltGraphState::UNINITIALIZED);
+}
+
+TEST(PrebuiltGraphTest, GraphConfigurationIssuesCorrectFunctionCalls) {
+ PrebuiltEngineInterfaceImpl callback;
+ std::shared_ptr<PrebuiltEngineInterface> engineInterface =
+ std::static_pointer_cast<PrebuiltEngineInterface, PrebuiltEngineInterfaceImpl>(
+ std::make_shared<PrebuiltEngineInterfaceImpl>(callback));
+ PrebuiltGraph* graph =
+ PrebuiltGraph::GetPrebuiltGraphFromLibrary("libstubgraphimpl.so", engineInterface);
+ ASSERT_TRUE(graph);
+ ASSERT_NE(graph->GetGraphState(), PrebuiltGraphState::UNINITIALIZED);
+
+ graph->GetSupportedGraphConfigs();
+ std::string functionVisited = graph->GetErrorMessage();
+ EXPECT_THAT(functionVisited, HasSubstr("GetSupportedGraphConfigs"));
+
+ std::map<int, int> maxOutputPacketsPerStream;
+ ClientConfig e(0, 0, 0, maxOutputPacketsPerStream);
+ e.setPhaseState(runner::PhaseState::ENTRY);
+ EXPECT_EQ(graph->handleConfigPhase(e), Status::SUCCESS);
+ functionVisited = graph->GetErrorMessage();
+
+ EXPECT_EQ(graph->GetStatus(), Status::SUCCESS);
+ functionVisited = graph->GetErrorMessage();
+ EXPECT_THAT(functionVisited, HasSubstr("GetErrorCode"));
+}
+
+TEST(PrebuiltGraphTest, GraphOperationEndToEndIsSuccessful) {
+ bool graphHasTerminated = false;
+ int numOutputStreamCallbacksReceived[4] = {0, 0, 0, 0};
+
+ PrebuiltEngineInterfaceImpl callback;
+ callback.SetGraphTerminationCallback(
+ [&graphHasTerminated](Status, std::string) { graphHasTerminated = true; });
+
+ // Add multiple pixel stream callback functions to see if all of them register.
+ callback.SetPixelCallback([&numOutputStreamCallbacksReceived](int streamIndex, int64_t,
+ const uint8_t*, int, int, int,
+ PixelFormat) {
+ ASSERT_TRUE(streamIndex == 0 || streamIndex == 1);
+ numOutputStreamCallbacksReceived[streamIndex]++;
+ });
+
+ // Add multiple stream callback functions to see if all of them register.
+ callback.SetSerializedStreamCallback(
+ [&numOutputStreamCallbacksReceived](int streamIndex, int64_t, std::string&&) {
+ ASSERT_TRUE(streamIndex == 2 || streamIndex == 3);
+ numOutputStreamCallbacksReceived[streamIndex]++;
+ });
+
+ std::shared_ptr<PrebuiltEngineInterface> engineInterface =
+ std::static_pointer_cast<PrebuiltEngineInterface, PrebuiltEngineInterfaceImpl>(
+ std::make_shared<PrebuiltEngineInterfaceImpl>(callback));
+
+ PrebuiltGraph* graph =
+ PrebuiltGraph::GetPrebuiltGraphFromLibrary("libstubgraphimpl.so", engineInterface);
+
+ ASSERT_NE(graph->GetGraphState(), PrebuiltGraphState::UNINITIALIZED);
+
+ graph->GetSupportedGraphConfigs();
+ std::string functionVisited = graph->GetErrorMessage();
+ EXPECT_THAT(functionVisited, HasSubstr("GetSupportedGraphConfigs"));
+
+ std::map<int, int> maxOutputPacketsPerStream;
+ ClientConfig e(0, 0, 0, maxOutputPacketsPerStream);
+ e.setPhaseState(runner::PhaseState::ENTRY);
+ EXPECT_EQ(graph->handleConfigPhase(e), Status::SUCCESS);
+ functionVisited = graph->GetErrorMessage();
+
+ EXPECT_EQ(graph->handleExecutionPhase(e), Status::SUCCESS);
+ functionVisited = graph->GetErrorMessage();
+ EXPECT_THAT(functionVisited, HasSubstr("StartGraphExecution"));
+
+ EXPECT_EQ(graph->SetInputStreamPixelData(
+ /*streamIndex =*/0, /*timestamp =*/0, /*pixels =*/nullptr,
+ /*width = */ 0, /*height =*/0, /*step =*/0, PixelFormat::RGB),
+ Status::SUCCESS);
+ EXPECT_EQ(graph->SetInputStreamPixelData(
+ /*streamIndex =*/0, /*timestamp =*/0, /*pixels =*/nullptr,
+ /*width = */ 0, /*height =*/0, /*step =*/0, PixelFormat::RGB),
+ Status::SUCCESS);
+ EXPECT_EQ(graph->SetInputStreamPixelData(
+ /*streamIndex =*/0, /*timestamp =*/0, /*pixels =*/nullptr,
+ /*width = */ 0, /*height =*/0, /*step =*/0, PixelFormat::RGB),
+ Status::SUCCESS);
+ EXPECT_EQ(graph->SetInputStreamPixelData(
+ /*streamIndex =*/1, /*timestamp =*/0, /*pixels =*/nullptr,
+ /*width = */ 0, /*height =*/0, /*step =*/0, PixelFormat::RGB),
+ Status::SUCCESS);
+ EXPECT_EQ(graph->SetInputStreamPixelData(
+ /*streamIndex =*/1, /*timestamp =*/0, /*pixels =*/nullptr,
+ /*width = */ 0, /*height =*/0, /*step =*/0, PixelFormat::RGB),
+ Status::SUCCESS);
+ functionVisited = graph->GetErrorMessage();
+ EXPECT_THAT(functionVisited, HasSubstr("SetInputStreamPixelData"));
+
+ EXPECT_EQ(graph->SetInputStreamData(/*streamIndex =*/2, /* timestamp =*/0, /* data =*/""),
+ Status::SUCCESS);
+ EXPECT_EQ(graph->SetInputStreamData(/*streamIndex =*/2, /* timestamp =*/0, /* data =*/""),
+ Status::SUCCESS);
+ EXPECT_EQ(graph->SetInputStreamData(/*streamIndex =*/2, /* timestamp =*/0, /* data =*/""),
+ Status::SUCCESS);
+ EXPECT_EQ(graph->SetInputStreamData(/*streamIndex =*/3, /* timestamp =*/0, /* data =*/""),
+ Status::SUCCESS);
+ EXPECT_EQ(graph->SetInputStreamData(/*streamIndex =*/3, /* timestamp =*/0, /* data =*/""),
+ Status::SUCCESS);
+ functionVisited = graph->GetErrorMessage();
+ EXPECT_THAT(functionVisited, HasSubstr("SetInputStreamData"));
+
+ EXPECT_EQ(numOutputStreamCallbacksReceived[0], 3);
+ EXPECT_EQ(numOutputStreamCallbacksReceived[1], 2);
+ EXPECT_EQ(numOutputStreamCallbacksReceived[2], 3);
+ EXPECT_EQ(numOutputStreamCallbacksReceived[3], 2);
+
+ EXPECT_FALSE(graphHasTerminated);
+ EXPECT_EQ(graph->handleStopImmediatePhase(e), Status::SUCCESS);
+
+ EXPECT_EQ(graph->handleResetPhase(e), Status::SUCCESS);
+ functionVisited = graph->GetErrorMessage();
+ EXPECT_THAT(functionVisited, HasSubstr("ResetGraph"));
+
+ EXPECT_TRUE(graphHasTerminated);
+}
+
+} // namespace
+} // namespace graph
+} // namespace computepipe
+} // namespace automotive
+} // namespace android
diff --git a/computepipe/tests/runner/graph/stubgraph/Android.bp b/computepipe/tests/runner/graph/stubgraph/Android.bp
new file mode 100644
index 0000000..d01b69f
--- /dev/null
+++ b/computepipe/tests/runner/graph/stubgraph/Android.bp
@@ -0,0 +1,41 @@
+// 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.
+
+cc_prebuilt_library_shared {
+ name: "libstubgraphimpl",
+ target: {
+ android_arm64: {
+ srcs: ["arm64/libstubgraphimpl.so"],
+ },
+ android_arm: {
+ srcs: ["arm/libstubgraphimpl.so"],
+ },
+ android_x86: {
+ srcs: ["x86/libstubgraphimpl.so"],
+ },
+ android_x86_64: {
+ srcs: ["x86_64/libstubgraphimpl.so"],
+ },
+ },
+
+ shared_libs: [
+ "libc",
+ "libdl",
+ "liblog",
+ "libm"
+ ],
+ strip: {
+ keep_symbols: true,
+ }
+}
diff --git a/computepipe/tests/runner/graph/stubgraph/arm/libstubgraphimpl.so b/computepipe/tests/runner/graph/stubgraph/arm/libstubgraphimpl.so
new file mode 100755
index 0000000..458b8ac
--- /dev/null
+++ b/computepipe/tests/runner/graph/stubgraph/arm/libstubgraphimpl.so
Binary files differ
diff --git a/computepipe/tests/runner/graph/stubgraph/arm64/libstubgraphimpl.so b/computepipe/tests/runner/graph/stubgraph/arm64/libstubgraphimpl.so
new file mode 100755
index 0000000..f6f6b3a
--- /dev/null
+++ b/computepipe/tests/runner/graph/stubgraph/arm64/libstubgraphimpl.so
Binary files differ
diff --git a/computepipe/tests/runner/graph/stubgraph/x86/libstubgraphimpl.so b/computepipe/tests/runner/graph/stubgraph/x86/libstubgraphimpl.so
new file mode 100755
index 0000000..6f71651
--- /dev/null
+++ b/computepipe/tests/runner/graph/stubgraph/x86/libstubgraphimpl.so
Binary files differ
diff --git a/computepipe/tests/runner/graph/stubgraph/x86_64/libstubgraphimpl.so b/computepipe/tests/runner/graph/stubgraph/x86_64/libstubgraphimpl.so
new file mode 100755
index 0000000..e4e7e75
--- /dev/null
+++ b/computepipe/tests/runner/graph/stubgraph/x86_64/libstubgraphimpl.so
Binary files differ
diff --git a/computepipe/types/Status.h b/computepipe/types/Status.h
index 4bd126f..af05c6a 100644
--- a/computepipe/types/Status.h
+++ b/computepipe/types/Status.h
@@ -26,6 +26,14 @@
ILLEGAL_STATE,
NO_MEMORY,
FATAL_ERROR,
+ STATUS_MAX,
+};
+
+enum PixelFormat {
+ RGB = 0,
+ RGBA,
+ GRAY,
+ PIXELFORMAT_MAX,
};
} // namespace computepipe