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 okay &= request->Set(mPlane->getId(), mPlane->getInFenceProperty(), inSyncFd.get());
87 okay &= request->Set(mPlane->getId(), mPlane->getFbProperty(), *buffer->mDrmFramebuffer);
88 okay &= request->Set(mPlane->getId(), mPlane->getCrtcXProperty(), 0);
89 okay &= request->Set(mPlane->getId(), mPlane->getCrtcYProperty(), 0);
90 okay &= request->Set(mPlane->getId(), mPlane->getCrtcWProperty(), buffer->mWidth);
91 okay &= request->Set(mPlane->getId(), mPlane->getCrtcHProperty(), buffer->mHeight);
92 okay &= request->Set(mPlane->getId(), mPlane->getSrcXProperty(), 0);
93 okay &= request->Set(mPlane->getId(), mPlane->getSrcYProperty(), 0);
94 okay &= request->Set(mPlane->getId(), mPlane->getSrcWProperty(), buffer->mWidth << 16);
95 okay &= request->Set(mPlane->getId(), mPlane->getSrcHProperty(), buffer->mHeight << 16);
96
97 okay &= request->Commit(drmFd);
98 if (!okay) {
99 ALOGE("%s: failed to flush to display.", __FUNCTION__);
100 return std::make_tuple(HWC3::Error::NoResources, ::android::base::unique_fd());
101 }
102
103 mPreviousBuffer = buffer;
104
105 DEBUG_LOG("%s: submitted atomic update, flush fence:%d\n", __FUNCTION__, flushFenceFd);
106 return std::make_tuple(HWC3::Error::None, ::android::base::unique_fd(flushFenceFd));
107 }
108
onConnect(::android::base::borrowed_fd drmFd)109 bool DrmDisplay::onConnect(::android::base::borrowed_fd drmFd) {
110 DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId);
111
112 auto request = DrmAtomicRequest::create();
113 if (!request) {
114 ALOGE("%s: display:%" PRIu32 " failed to create atomic request.", __FUNCTION__, mId);
115 return false;
116 }
117
118 bool okay = true;
119 okay &= request->Set(mConnector->getId(), mConnector->getCrtcProperty(), mCrtc->getId());
120 okay &= request->Set(mCrtc->getId(), mCrtc->getActiveProperty(), 1);
121 okay &= request->Set(mCrtc->getId(), mCrtc->getModeProperty(),
122 mConnector->getDefaultMode()->getBlobId());
123
124 okay &= request->Commit(drmFd);
125 if (!okay) {
126 ALOGE("%s: display:%" PRIu32 " failed to set mode.", __FUNCTION__, mId);
127 return false;
128 }
129
130 return true;
131 }
132
onDisconnect(::android::base::borrowed_fd drmFd)133 bool DrmDisplay::onDisconnect(::android::base::borrowed_fd drmFd) {
134 DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId);
135
136 auto request = DrmAtomicRequest::create();
137 if (!request) {
138 ALOGE("%s: display:%" PRIu32 " failed to create atomic request.", __FUNCTION__, mId);
139 return false;
140 }
141
142 bool okay = true;
143 okay &= request->Set(mPlane->getId(), mPlane->getCrtcProperty(), 0);
144 okay &= request->Set(mPlane->getId(), mPlane->getFbProperty(), 0);
145
146 okay &= request->Commit(drmFd);
147 if (!okay) {
148 ALOGE("%s: display:%" PRIu32 " failed to set mode", __FUNCTION__, mId);
149 }
150
151 mPreviousBuffer.reset();
152
153 return okay;
154 }
155
checkAndHandleHotplug(::android::base::borrowed_fd drmFd)156 DrmHotplugChange DrmDisplay::checkAndHandleHotplug(::android::base::borrowed_fd drmFd) {
157 DEBUG_LOG("%s: display:%" PRIu32, __FUNCTION__, mId);
158
159 const bool oldConnected = mConnector->isConnected();
160 mConnector->update(drmFd);
161 const bool newConnected = mConnector->isConnected();
162
163 if (oldConnected == newConnected) {
164 return DrmHotplugChange::kNoChange;
165 }
166
167 if (newConnected) {
168 ALOGI("%s: display:%" PRIu32 " was connected.", __FUNCTION__, mId);
169 if (!onConnect(drmFd)) {
170 ALOGE("%s: display:%" PRIu32 " failed to connect.", __FUNCTION__, mId);
171 }
172 return DrmHotplugChange::kConnected;
173 } else {
174 ALOGI("%s: display:%" PRIu32 " was disconnected.", __FUNCTION__, mId);
175 if (!onDisconnect(drmFd)) {
176 ALOGE("%s: display:%" PRIu32 " failed to disconnect.", __FUNCTION__, mId);
177 }
178 return DrmHotplugChange::kDisconnected;
179 }
180 }
181
182 } // namespace aidl::android::hardware::graphics::composer3::impl
183