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