// 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 #include #include #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& 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(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 lk(mLock); mStopThread = true; mWait.notify_one(); } if (mThread.joinable()) { mThread.join(); } } void EvsDisplayManager::threadFn() { sp evsEnumerator = IEvsEnumerator::getService(std::string() + kServiceName); if (!mOverrideDisplayId) { evsEnumerator->getDisplayIdList([this] (auto ids) { this->mDisplayId = ids[ids.size() - 1]; }); } android::sp 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(result); evsEnumerator->closeDisplay(evsDisplay); return; } if (!evsRenderer.activate()) { mStopThread = true; LOG(ERROR) << "Unable to activate evs renderer."; evsEnumerator->closeDisplay(evsDisplay); return; } std::unique_lock 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 freePacketCallback) { std::lock_guard lk(mLock); mFreePacketCallback = freePacketCallback; } Status EvsDisplayManager::displayFrame(const std::shared_ptr& dataHandle) { std::lock_guard 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 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