blob: 404f06f18062615e8e09f5f0e1841d6aac2af7a0 [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.
#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
#include <android-base/logging.h>
#include "EvsDisplayManager.h"
#include "PixelFormatUtils.h"
#include "RenderDirectView.h"
namespace android {
namespace automotive {
namespace computepipe {
namespace runner {
namespace debug_display_manager {
namespace {
constexpr char kServiceName[] = "default";
using android::hardware::automotive::evs::V1_1::IEvsEnumerator;
using android::hardware::automotive::evs::V1_1::IEvsDisplay;
using android::hardware::automotive::evs::V1_0::EvsResult;
using android::hardware::automotive::evs::V1_0::DisplayState;
using android::hardware::automotive::evs::V1_0::BufferDesc;
using android::automotive::evs::support::RenderDirectView;
BufferDesc getBufferDesc(const std::shared_ptr<MemHandle>& frame) {
AHardwareBuffer_Desc hwDesc;
AHardwareBuffer_describe(frame->getHardwareBuffer(), &hwDesc);
BufferDesc buffer;
buffer.width = hwDesc.width;
buffer.height = hwDesc.height;
buffer.stride = hwDesc.stride;
buffer.pixelSize = numBytesPerPixel(static_cast<AHardwareBuffer_Format>(hwDesc.format));
buffer.format = hwDesc.format;
buffer.usage = hwDesc.usage;
buffer.memHandle = AHardwareBuffer_getNativeHandle(frame->getHardwareBuffer());
return buffer;
}
} // namespace
EvsDisplayManager::~EvsDisplayManager() {
stopThread();
}
Status EvsDisplayManager::setArgs(std::string displayManagerArgs) {
auto pos = displayManagerArgs.find(kDisplayId);
if (pos == std::string::npos) {
return Status::SUCCESS;
}
mDisplayId = std::stoi(displayManagerArgs.substr(pos + strlen(kDisplayId)));
mOverrideDisplayId = true;
return Status::SUCCESS;
}
void EvsDisplayManager::stopThread() {
{
std::lock_guard<std::mutex> lk(mLock);
mStopThread = true;
mWait.notify_one();
}
if (mThread.joinable()) {
mThread.join();
}
}
void EvsDisplayManager::threadFn() {
sp<IEvsEnumerator> evsEnumerator = IEvsEnumerator::getService(std::string() + kServiceName);
if (!mOverrideDisplayId) {
evsEnumerator->getDisplayIdList([this] (auto ids) {
this->mDisplayId = ids[ids.size() - 1];
});
}
android::sp <IEvsDisplay> evsDisplay = evsEnumerator->openDisplay_1_1(mDisplayId);
if (evsDisplay != nullptr) {
LOG(INFO) << "Computepipe runner opened debug display.";
} else {
mStopThread = true;
LOG(ERROR) << "EVS Display unavailable. Exiting thread.";
return;
}
RenderDirectView evsRenderer;
EvsResult result = evsDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
if (result != EvsResult::OK) {
mStopThread = true;
LOG(ERROR) << "Set display state returned error - " << static_cast<int>(result);
evsEnumerator->closeDisplay(evsDisplay);
return;
}
if (!evsRenderer.activate()) {
mStopThread = true;
LOG(ERROR) << "Unable to activate evs renderer.";
evsEnumerator->closeDisplay(evsDisplay);
return;
}
std::unique_lock<std::mutex> lk(mLock);
while (true) {
mWait.wait(lk, [this]() { return mNextFrame != nullptr || mStopThread; });
if (mStopThread) {
// Free unused frame.
if (mFreePacketCallback && mNextFrame) {
mFreePacketCallback(mNextFrame->getBufferId());
}
break;
}
BufferDesc tgtBuffer = {};
evsDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc& buff) {
tgtBuffer = buff;
}
);
BufferDesc srcBuffer = getBufferDesc(mNextFrame);
if (!evsRenderer.drawFrame(tgtBuffer, srcBuffer)) {
LOG(ERROR) << "Error in rendering a frame.";
mStopThread = true;
}
evsDisplay->returnTargetBufferForDisplay(tgtBuffer);
if (mFreePacketCallback) {
mFreePacketCallback(mNextFrame->getBufferId());
}
mNextFrame = nullptr;
}
LOG(INFO) << "Computepipe runner closing debug display.";
evsRenderer.deactivate();
(void)evsDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
evsEnumerator->closeDisplay(evsDisplay);
}
void EvsDisplayManager::setFreePacketCallback(
std::function<Status(int bufferId)> freePacketCallback) {
std::lock_guard<std::mutex> lk(mLock);
mFreePacketCallback = freePacketCallback;
}
Status EvsDisplayManager::displayFrame(const std::shared_ptr<MemHandle>& dataHandle) {
std::lock_guard<std::mutex> lk(mLock);
Status status = Status::SUCCESS;
if (mStopThread) {
return Status::ILLEGAL_STATE;
}
if (mNextFrame != nullptr && mFreePacketCallback) {
status = mFreePacketCallback(mNextFrame->getBufferId());
}
mNextFrame = dataHandle;
mWait.notify_one();
return status;
}
Status EvsDisplayManager::handleExecutionPhase(const RunnerEvent& e) {
if (e.isPhaseEntry()) {
std::lock_guard<std::mutex> lk(mLock);
mStopThread = false;
mThread = std::thread(&EvsDisplayManager::threadFn, this);
} else if (e.isAborted()) {
stopThread();
}
return Status::SUCCESS;
}
Status EvsDisplayManager::handleStopWithFlushPhase(const RunnerEvent& /* e */) {
stopThread();
return Status::SUCCESS;
}
Status EvsDisplayManager::handleStopImmediatePhase(const RunnerEvent& /* e */) {
stopThread();
return Status::SUCCESS;
}
Status EvsDisplayManager::handleResetPhase(const RunnerEvent& /* e */) {
stopThread();
return Status::SUCCESS;
}
} // namespace debug_display_manager
} // namespace runner
} // namespace computepipe
} // namespace automotive
} // namespace android