1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "DrmDisplay.h"
18 
19 #include "DrmAtomicRequest.h"
20 
21 namespace aidl::android::hardware::graphics::composer3::impl {
22 namespace {
23 
24 template <typename T>
addressAsUint(T * pointer)25 uint64_t addressAsUint(T* pointer) {
26     return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pointer));
27 }
28 
29 }  // namespace
30 
create(uint32_t id,std::unique_ptr<DrmConnector> connector,std::unique_ptr<DrmCrtc> crtc,std::unique_ptr<DrmPlane> plane,::android::base::borrowed_fd drmFd)31 std::unique_ptr<DrmDisplay> DrmDisplay::create(uint32_t id, std::unique_ptr<DrmConnector> connector,
32                                                std::unique_ptr<DrmCrtc> crtc,
33                                                std::unique_ptr<DrmPlane> plane,
34                                                ::android::base::borrowed_fd drmFd) {
35     if (!crtc) {
36         ALOGE("%s: invalid crtc.", __FUNCTION__);
37         return nullptr;
38     }
39     if (!connector) {
40         ALOGE("%s: invalid connector.", __FUNCTION__);
41         return nullptr;
42     }
43     if (!plane) {
44         ALOGE("%s: invalid plane.", __FUNCTION__);
45         return nullptr;
46     }
47 
48     if (connector->isConnected()) {
49         auto request = DrmAtomicRequest::create();
50         if (!request) {
51             ALOGE("%s: failed to create atomic request.", __FUNCTION__);
52             return nullptr;
53         }
54 
55         bool okay = true;
56         okay &= request->Set(connector->getId(), connector->getCrtcProperty(), crtc->getId());
57         okay &= request->Set(crtc->getId(), crtc->getActiveProperty(), 1);
58         okay &= request->Set(crtc->getId(), crtc->getModeProperty(),
59                              connector->getDefaultMode()->getBlobId());
60         okay &= request->Commit(drmFd);
61         if (!okay) {
62             ALOGE("%s: failed to set display mode.", __FUNCTION__);
63             return nullptr;
64         }
65     }
66 
67     return std::unique_ptr<DrmDisplay>(
68         new DrmDisplay(id, std::move(connector), std::move(crtc), std::move(plane)));
69 }
70 
flush(::android::base::borrowed_fd drmFd,::android::base::borrowed_fd inSyncFd,const std::shared_ptr<DrmBuffer> & buffer)71 std::tuple<HWC3::Error, ::android::base::unique_fd> DrmDisplay::flush(
72     ::android::base::borrowed_fd drmFd, ::android::base::borrowed_fd inSyncFd,
73     const std::shared_ptr<DrmBuffer>& buffer) {
74     std::unique_ptr<DrmAtomicRequest> request = DrmAtomicRequest::create();
75     if (!request) {
76         ALOGE("%s: failed to create atomic request.", __FUNCTION__);
77         return std::make_tuple(HWC3::Error::NoResources, ::android::base::unique_fd());
78     }
79 
80     int flushFenceFd = -1;
81 
82     bool okay = true;
83     okay &=
84         request->Set(mCrtc->getId(), mCrtc->getOutFenceProperty(), addressAsUint(&flushFenceFd));
85     okay &= request->Set(mPlane->getId(), mPlane->getCrtcProperty(), mCrtc->getId());
86     if (inSyncFd != -1) {
87         okay &= request->Set(mPlane->getId(), mPlane->getInFenceProperty(),
88                              static_cast<uint64_t>(inSyncFd.get()));
89     }
90     okay &= request->Set(mPlane->getId(), mPlane->getFbProperty(), *buffer->mDrmFramebuffer);
91     okay &= request->Set(mPlane->getId(), mPlane->getCrtcXProperty(), 0);
92     okay &= request->Set(mPlane->getId(), mPlane->getCrtcYProperty(), 0);
93     okay &= request->Set(mPlane->getId(), mPlane->getCrtcWProperty(), buffer->mWidth);
94     okay &= request->Set(mPlane->getId(), mPlane->getCrtcHProperty(), buffer->mHeight);
95     okay &= request->Set(mPlane->getId(), mPlane->getSrcXProperty(), 0);
96     okay &= request->Set(mPlane->getId(), mPlane->getSrcYProperty(), 0);
97     okay &= request->Set(mPlane->getId(), mPlane->getSrcWProperty(), buffer->mWidth << 16);
98     okay &= request->Set(mPlane->getId(), mPlane->getSrcHProperty(), buffer->mHeight << 16);
99 
100     okay &= request->Commit(drmFd);
101     if (!okay) {
102         ALOGE("%s: failed to flush to display.", __FUNCTION__);
103         return std::make_tuple(HWC3::Error::NoResources, ::android::base::unique_fd());
104     }
105 
106     mPreviousBuffer = buffer;
107 
108     DEBUG_LOG("%s: submitted atomic update, flush fence:%d\n", __FUNCTION__, flushFenceFd);
109     return std::make_tuple(HWC3::Error::None, ::android::base::unique_fd(flushFenceFd));
110 }
111 
onConnect(::android::base::borrowed_fd drmFd)112 bool DrmDisplay::onConnect(::android::base::borrowed_fd drmFd) {
113     DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId);
114 
115     auto request = DrmAtomicRequest::create();
116     if (!request) {
117         ALOGE("%s: display:%" PRIu32 " failed to create atomic request.", __FUNCTION__, mId);
118         return false;
119     }
120 
121     bool okay = true;
122     okay &= request->Set(mConnector->getId(), mConnector->getCrtcProperty(), mCrtc->getId());
123     okay &= request->Set(mCrtc->getId(), mCrtc->getActiveProperty(), 1);
124     okay &= request->Set(mCrtc->getId(), mCrtc->getModeProperty(),
125                          mConnector->getDefaultMode()->getBlobId());
126 
127     okay &= request->Commit(drmFd);
128     if (!okay) {
129         ALOGE("%s: display:%" PRIu32 " failed to set mode.", __FUNCTION__, mId);
130         return false;
131     }
132 
133     return true;
134 }
135 
onDisconnect(::android::base::borrowed_fd drmFd)136 bool DrmDisplay::onDisconnect(::android::base::borrowed_fd drmFd) {
137     DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId);
138 
139     auto request = DrmAtomicRequest::create();
140     if (!request) {
141         ALOGE("%s: display:%" PRIu32 " failed to create atomic request.", __FUNCTION__, mId);
142         return false;
143     }
144 
145     bool okay = true;
146     okay &= request->Set(mPlane->getId(), mPlane->getCrtcProperty(), 0);
147     okay &= request->Set(mPlane->getId(), mPlane->getFbProperty(), 0);
148 
149     okay &= request->Commit(drmFd);
150     if (!okay) {
151         ALOGE("%s: display:%" PRIu32 " failed to set mode", __FUNCTION__, mId);
152     }
153 
154     mPreviousBuffer.reset();
155 
156     return okay;
157 }
158 
checkAndHandleHotplug(::android::base::borrowed_fd drmFd)159 DrmHotplugChange DrmDisplay::checkAndHandleHotplug(::android::base::borrowed_fd drmFd) {
160     DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId);
161 
162     const bool oldConnected = mConnector->isConnected();
163     mConnector->update(drmFd);
164     const bool newConnected = mConnector->isConnected();
165 
166     if (oldConnected == newConnected) {
167         return DrmHotplugChange::kNoChange;
168     }
169 
170     if (newConnected) {
171         ALOGI("%s: display:%" PRIu32 " was connected.", __FUNCTION__, mId);
172         if (!onConnect(drmFd)) {
173             ALOGE("%s: display:%" PRIu32 " failed to connect.", __FUNCTION__, mId);
174         }
175         return DrmHotplugChange::kConnected;
176     } else {
177         ALOGI("%s: display:%" PRIu32 " was disconnected.", __FUNCTION__, mId);
178         if (!onDisconnect(drmFd)) {
179             ALOGE("%s: display:%" PRIu32 " failed to disconnect.", __FUNCTION__, mId);
180         }
181         return DrmHotplugChange::kDisconnected;
182     }
183 }
184 
185 }  // namespace aidl::android::hardware::graphics::composer3::impl
186