/* * Copyright 2022 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 "DrmDisplay.h" #include "DrmAtomicRequest.h" namespace aidl::android::hardware::graphics::composer3::impl { namespace { template uint64_t addressAsUint(T* pointer) { return static_cast(reinterpret_cast(pointer)); } } // namespace std::unique_ptr DrmDisplay::create(uint32_t id, std::unique_ptr connector, std::unique_ptr crtc, std::unique_ptr plane, ::android::base::borrowed_fd drmFd) { if (!crtc) { ALOGE("%s: invalid crtc.", __FUNCTION__); return nullptr; } if (!connector) { ALOGE("%s: invalid connector.", __FUNCTION__); return nullptr; } if (!plane) { ALOGE("%s: invalid plane.", __FUNCTION__); return nullptr; } if (connector->isConnected()) { auto request = DrmAtomicRequest::create(); if (!request) { ALOGE("%s: failed to create atomic request.", __FUNCTION__); return nullptr; } bool okay = true; okay &= request->Set(connector->getId(), connector->getCrtcProperty(), crtc->getId()); okay &= request->Set(crtc->getId(), crtc->getActiveProperty(), 1); okay &= request->Set(crtc->getId(), crtc->getModeProperty(), connector->getDefaultMode()->getBlobId()); okay &= request->Commit(drmFd); if (!okay) { ALOGE("%s: failed to set display mode.", __FUNCTION__); return nullptr; } } return std::unique_ptr( new DrmDisplay(id, std::move(connector), std::move(crtc), std::move(plane))); } std::tuple DrmDisplay::flush( ::android::base::borrowed_fd drmFd, ::android::base::borrowed_fd inSyncFd, const std::shared_ptr& buffer) { std::unique_ptr request = DrmAtomicRequest::create(); if (!request) { ALOGE("%s: failed to create atomic request.", __FUNCTION__); return std::make_tuple(HWC3::Error::NoResources, ::android::base::unique_fd()); } int flushFenceFd = -1; bool okay = true; okay &= request->Set(mCrtc->getId(), mCrtc->getOutFenceProperty(), addressAsUint(&flushFenceFd)); okay &= request->Set(mPlane->getId(), mPlane->getCrtcProperty(), mCrtc->getId()); if (inSyncFd != -1) { okay &= request->Set(mPlane->getId(), mPlane->getInFenceProperty(), static_cast(inSyncFd.get())); } okay &= request->Set(mPlane->getId(), mPlane->getFbProperty(), *buffer->mDrmFramebuffer); okay &= request->Set(mPlane->getId(), mPlane->getCrtcXProperty(), 0); okay &= request->Set(mPlane->getId(), mPlane->getCrtcYProperty(), 0); okay &= request->Set(mPlane->getId(), mPlane->getCrtcWProperty(), buffer->mWidth); okay &= request->Set(mPlane->getId(), mPlane->getCrtcHProperty(), buffer->mHeight); okay &= request->Set(mPlane->getId(), mPlane->getSrcXProperty(), 0); okay &= request->Set(mPlane->getId(), mPlane->getSrcYProperty(), 0); okay &= request->Set(mPlane->getId(), mPlane->getSrcWProperty(), buffer->mWidth << 16); okay &= request->Set(mPlane->getId(), mPlane->getSrcHProperty(), buffer->mHeight << 16); okay &= request->Commit(drmFd); if (!okay) { ALOGE("%s: failed to flush to display.", __FUNCTION__); return std::make_tuple(HWC3::Error::NoResources, ::android::base::unique_fd()); } mPreviousBuffer = buffer; DEBUG_LOG("%s: submitted atomic update, flush fence:%d\n", __FUNCTION__, flushFenceFd); return std::make_tuple(HWC3::Error::None, ::android::base::unique_fd(flushFenceFd)); } bool DrmDisplay::onConnect(::android::base::borrowed_fd drmFd) { DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId); auto request = DrmAtomicRequest::create(); if (!request) { ALOGE("%s: display:%" PRIu32 " failed to create atomic request.", __FUNCTION__, mId); return false; } bool okay = true; okay &= request->Set(mConnector->getId(), mConnector->getCrtcProperty(), mCrtc->getId()); okay &= request->Set(mCrtc->getId(), mCrtc->getActiveProperty(), 1); okay &= request->Set(mCrtc->getId(), mCrtc->getModeProperty(), mConnector->getDefaultMode()->getBlobId()); okay &= request->Commit(drmFd); if (!okay) { ALOGE("%s: display:%" PRIu32 " failed to set mode.", __FUNCTION__, mId); return false; } return true; } bool DrmDisplay::onDisconnect(::android::base::borrowed_fd drmFd) { DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId); auto request = DrmAtomicRequest::create(); if (!request) { ALOGE("%s: display:%" PRIu32 " failed to create atomic request.", __FUNCTION__, mId); return false; } bool okay = true; okay &= request->Set(mPlane->getId(), mPlane->getCrtcProperty(), 0); okay &= request->Set(mPlane->getId(), mPlane->getFbProperty(), 0); okay &= request->Commit(drmFd); if (!okay) { ALOGE("%s: display:%" PRIu32 " failed to set mode", __FUNCTION__, mId); } mPreviousBuffer.reset(); return okay; } DrmHotplugChange DrmDisplay::checkAndHandleHotplug(::android::base::borrowed_fd drmFd) { DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId); const bool oldConnected = mConnector->isConnected(); mConnector->update(drmFd); const bool newConnected = mConnector->isConnected(); if (oldConnected == newConnected) { return DrmHotplugChange::kNoChange; } if (newConnected) { ALOGI("%s: display:%" PRIu32 " was connected.", __FUNCTION__, mId); if (!onConnect(drmFd)) { ALOGE("%s: display:%" PRIu32 " failed to connect.", __FUNCTION__, mId); } return DrmHotplugChange::kConnected; } else { ALOGI("%s: display:%" PRIu32 " was disconnected.", __FUNCTION__, mId); if (!onDisconnect(drmFd)) { ALOGE("%s: display:%" PRIu32 " failed to disconnect.", __FUNCTION__, mId); } return DrmHotplugChange::kDisconnected; } } } // namespace aidl::android::hardware::graphics::composer3::impl