blob: 3816c1bc4f752bdd9121057a5b3d11d2de394d7c [file] [log] [blame]
Jiwen 'Steve' Cai8f51ec62018-08-07 21:50:51 -07001/*
2 * Copyright (C) 2018 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// We would eliminate the clang warnings introduced by libdpx.
18// TODO(b/112338294): Remove those once BufferHub moved to use Binder
19#pragma clang diagnostic push
20#pragma clang diagnostic ignored "-Wconversion"
21#pragma clang diagnostic ignored "-Wdouble-promotion"
22#pragma clang diagnostic ignored "-Wgnu-case-range"
23#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
24#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
25#pragma clang diagnostic ignored "-Wnested-anon-types"
26#pragma clang diagnostic ignored "-Wpacked"
27#pragma clang diagnostic ignored "-Wshadow"
28#pragma clang diagnostic ignored "-Wsign-conversion"
29#pragma clang diagnostic ignored "-Wswitch-enum"
30#pragma clang diagnostic ignored "-Wundefined-func-template"
31#pragma clang diagnostic ignored "-Wunused-template"
32#pragma clang diagnostic ignored "-Wweak-vtables"
Jiwen 'Steve' Cai088b3b62018-10-03 18:49:07 -070033#include <pdx/default_transport/client_channel.h>
34#include <pdx/default_transport/client_channel_factory.h>
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -070035#include <pdx/file_handle.h>
Jiwen 'Steve' Cai088b3b62018-10-03 18:49:07 -070036#include <private/dvr/bufferhub_rpc.h>
Jiwen 'Steve' Cai8f51ec62018-08-07 21:50:51 -070037#pragma clang diagnostic pop
38
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070039#include <poll.h>
40
Fan Xu069e8382018-11-16 16:28:08 -080041#include <android-base/unique_fd.h>
42#include <ui/BufferHubBuffer.h>
43
44using android::base::unique_fd;
Jiwen 'Steve' Cai8f51ec62018-08-07 21:50:51 -070045using android::dvr::BufferTraits;
46using android::dvr::DetachedBufferRPC;
47using android::dvr::NativeHandleWrapper;
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070048
49// TODO(b/112338294): Remove PDX dependencies from libui.
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070050using android::pdx::LocalChannelHandle;
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -070051using android::pdx::LocalHandle;
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070052using android::pdx::Status;
Jiwen 'Steve' Cai088b3b62018-10-03 18:49:07 -070053using android::pdx::default_transport::ClientChannel;
54using android::pdx::default_transport::ClientChannelFactory;
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -070055
56namespace android {
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -070057
Jiwen 'Steve' Cai9004b8c2018-10-03 18:52:23 -070058namespace {
59
60// TODO(b/112338294): Remove this string literal after refactoring BufferHub
61// to use Binder.
62static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client";
63
Tianyu Jiangb08b7222018-11-16 17:55:26 -080064using dvr::BufferHubDefs::AnyClientAcquired;
65using dvr::BufferHubDefs::AnyClientGained;
66using dvr::BufferHubDefs::AnyClientPosted;
67using dvr::BufferHubDefs::IsClientAcquired;
68using dvr::BufferHubDefs::IsClientGained;
69using dvr::BufferHubDefs::IsClientPosted;
70using dvr::BufferHubDefs::IsClientReleased;
71using dvr::BufferHubDefs::kHighBitsMask;
72using dvr::BufferHubDefs::kMetadataHeaderSize;
73
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070074} // namespace
Jiwen 'Steve' Cai9004b8c2018-10-03 18:52:23 -070075
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070076BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(kBufferHubClientPath)) {}
Jiwen 'Steve' Cai088b3b62018-10-03 18:49:07 -070077
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070078BufferHubClient::BufferHubClient(LocalChannelHandle mChannelHandle)
79 : Client(ClientChannel::Create(std::move(mChannelHandle))) {}
Jiwen 'Steve' Cai088b3b62018-10-03 18:49:07 -070080
Jiwen 'Steve' Cai8f51ec62018-08-07 21:50:51 -070081BufferHubClient::~BufferHubClient() {}
82
Jiwen 'Steve' Cai088b3b62018-10-03 18:49:07 -070083bool BufferHubClient::IsValid() const {
Tianyu Jiangb08b7222018-11-16 17:55:26 -080084 return IsConnected() && GetChannelHandle().valid();
Jiwen 'Steve' Cai088b3b62018-10-03 18:49:07 -070085}
86
87LocalChannelHandle BufferHubClient::TakeChannelHandle() {
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070088 if (IsConnected()) {
89 return std::move(GetChannelHandle());
90 } else {
91 return {};
92 }
93}
94
95BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
96 uint32_t format, uint64_t usage, size_t mUserMetadataSize) {
97 ATRACE_CALL();
98 ALOGD("BufferHubBuffer::BufferHubBuffer: width=%u height=%u layerCount=%u, format=%u "
99 "usage=%" PRIx64 " mUserMetadataSize=%zu",
100 width, height, layerCount, format, usage, mUserMetadataSize);
101
102 auto status =
103 mClient.InvokeRemoteMethod<DetachedBufferRPC::Create>(width, height, layerCount, format,
104 usage, mUserMetadataSize);
105 if (!status) {
106 ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to create detached buffer: %s",
107 status.GetErrorMessage().c_str());
108 mClient.Close(-status.error());
109 }
110
111 const int ret = ImportGraphicBuffer();
112 if (ret < 0) {
113 ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import buffer: %s", strerror(-ret));
114 mClient.Close(ret);
115 }
116}
117
118BufferHubBuffer::BufferHubBuffer(LocalChannelHandle mChannelHandle)
119 : mClient(std::move(mChannelHandle)) {
120 const int ret = ImportGraphicBuffer();
121 if (ret < 0) {
122 ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import buffer: %s", strerror(-ret));
123 mClient.Close(ret);
124 }
125}
126
127int BufferHubBuffer::ImportGraphicBuffer() {
128 ATRACE_CALL();
129
130 auto status = mClient.InvokeRemoteMethod<DetachedBufferRPC::Import>();
131 if (!status) {
132 ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import GraphicBuffer: %s",
133 status.GetErrorMessage().c_str());
134 return -status.error();
135 }
136
137 BufferTraits<LocalHandle> bufferTraits = status.take();
138 if (bufferTraits.id() < 0) {
139 ALOGE("BufferHubBuffer::BufferHubBuffer: Received an invalid id!");
140 return -EIO;
141 }
142
143 // Stash the buffer id to replace the value in mId.
144 const int bufferId = bufferTraits.id();
145
146 // Import the metadata.
Fan Xu069e8382018-11-16 16:28:08 -0800147 LocalHandle metadataHandle = bufferTraits.take_metadata_handle();
148 unique_fd metadataFd(metadataHandle.Release());
149 mMetadata = BufferHubMetadata::Import(std::move(metadataFd));
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700150
151 if (!mMetadata.IsValid()) {
152 ALOGE("BufferHubBuffer::ImportGraphicBuffer: invalid metadata.");
153 return -ENOMEM;
154 }
155
156 if (mMetadata.metadata_size() != bufferTraits.metadata_size()) {
157 ALOGE("BufferHubBuffer::ImportGraphicBuffer: metadata buffer too small: "
158 "%zu, expected: %" PRIu64 ".",
159 mMetadata.metadata_size(), bufferTraits.metadata_size());
160 return -ENOMEM;
161 }
162
163 size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size());
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800164 if (metadataSize < kMetadataHeaderSize) {
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700165 ALOGE("BufferHubBuffer::ImportGraphicBuffer: metadata too small: %zu", metadataSize);
166 return -EINVAL;
167 }
168
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800169 // Populate shortcuts to the atomics in metadata.
170 auto metadata_header = mMetadata.metadata_header();
171 buffer_state_ = &metadata_header->buffer_state;
172 fence_state_ = &metadata_header->fence_state;
173 active_clients_bit_mask_ = &metadata_header->active_clients_bit_mask;
174
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700175 // Import the buffer: We only need to hold on the native_handle_t here so that
176 // GraphicBuffer instance can be created in future.
177 mBufferHandle = bufferTraits.take_buffer_handle();
178
Jiwen 'Steve' Cai2daf5182018-10-16 00:14:03 -0700179 // Populate buffer desc based on buffer traits.
180 mBufferDesc.width = bufferTraits.width();
181 mBufferDesc.height = bufferTraits.height();
182 mBufferDesc.layers = bufferTraits.layer_count();
183 mBufferDesc.format = bufferTraits.format();
184 mBufferDesc.usage = bufferTraits.usage();
185 mBufferDesc.stride = bufferTraits.stride();
186 mBufferDesc.rfu0 = 0U;
187 mBufferDesc.rfu1 = 0U;
188
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700189 // If all imports succeed, replace the previous buffer and id.
190 mId = bufferId;
Tianyu Jiang7e204b72018-10-26 15:39:18 -0700191 mClientStateMask = bufferTraits.client_state_mask();
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700192
193 // TODO(b/112012161) Set up shared fences.
194 ALOGD("BufferHubBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64 ".", id(),
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800195 buffer_state_->load(std::memory_order_acquire));
196 return 0;
197}
198
199int BufferHubBuffer::Gain() {
200 uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
201 if (IsClientGained(current_buffer_state, mClientStateMask)) {
202 ALOGV("%s: Buffer is already gained by this client %" PRIx64 ".", __FUNCTION__,
203 mClientStateMask);
204 return 0;
205 }
206 do {
207 if (AnyClientGained(current_buffer_state & (~mClientStateMask)) ||
208 AnyClientAcquired(current_buffer_state)) {
209 ALOGE("%s: Buffer is in use, id=%d mClientStateMask=%" PRIx64 " state=%" PRIx64 ".",
210 __FUNCTION__, mId, mClientStateMask, current_buffer_state);
211 return -EBUSY;
212 }
213 // Change the buffer state to gained state, whose value happens to be the same as
214 // mClientStateMask.
215 } while (!buffer_state_->compare_exchange_weak(current_buffer_state, mClientStateMask,
216 std::memory_order_acq_rel,
217 std::memory_order_acquire));
218 // TODO(b/119837586): Update fence state and return GPU fence.
219 return 0;
220}
221
222int BufferHubBuffer::Post() {
223 uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
224 uint64_t current_active_clients_bit_mask = 0ULL;
225 uint64_t updated_buffer_state = 0ULL;
226 do {
227 if (!IsClientGained(current_buffer_state, mClientStateMask)) {
228 ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d "
229 "mClientStateMask=%" PRIx64 " state=%" PRIx64 ".",
230 __FUNCTION__, mId, mClientStateMask, current_buffer_state);
231 return -EBUSY;
232 }
233 // Set the producer client buffer state to released, other clients' buffer state to posted.
234 current_active_clients_bit_mask = active_clients_bit_mask_->load(std::memory_order_acquire);
235 updated_buffer_state =
236 current_active_clients_bit_mask & (~mClientStateMask) & kHighBitsMask;
237 } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
238 std::memory_order_acq_rel,
239 std::memory_order_acquire));
240 // TODO(b/119837586): Update fence state and return GPU fence if needed.
241 return 0;
242}
243
244int BufferHubBuffer::Acquire() {
245 uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
246 if (IsClientAcquired(current_buffer_state, mClientStateMask)) {
247 ALOGV("%s: Buffer is already acquired by this client %" PRIx64 ".", __FUNCTION__,
248 mClientStateMask);
249 return 0;
250 }
251 uint64_t updated_buffer_state = 0ULL;
252 do {
253 if (!IsClientPosted(current_buffer_state, mClientStateMask)) {
254 ALOGE("%s: Cannot acquire a buffer that is not in posted state. buffer_id=%d "
255 "mClientStateMask=%" PRIx64 " state=%" PRIx64 ".",
256 __FUNCTION__, mId, mClientStateMask, current_buffer_state);
257 return -EBUSY;
258 }
259 // Change the buffer state for this consumer from posted to acquired.
260 updated_buffer_state = current_buffer_state ^ mClientStateMask;
261 } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
262 std::memory_order_acq_rel,
263 std::memory_order_acquire));
264 // TODO(b/119837586): Update fence state and return GPU fence.
265 return 0;
266}
267
268int BufferHubBuffer::Release() {
269 uint64_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
270 if (IsClientReleased(current_buffer_state, mClientStateMask)) {
271 ALOGV("%s: Buffer is already released by this client %" PRIx64 ".", __FUNCTION__,
272 mClientStateMask);
273 return 0;
274 }
275 uint64_t updated_buffer_state = 0ULL;
276 do {
277 updated_buffer_state = current_buffer_state & (~mClientStateMask);
278 } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
279 std::memory_order_acq_rel,
280 std::memory_order_acquire));
281 // TODO(b/119837586): Update fence state and return GPU fence if needed.
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700282 return 0;
283}
284
285int BufferHubBuffer::Poll(int timeoutMs) {
286 ATRACE_CALL();
287
288 pollfd p = {mClient.event_fd(), POLLIN, 0};
289 return poll(&p, 1, timeoutMs);
290}
291
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700292Status<LocalChannelHandle> BufferHubBuffer::Duplicate() {
293 ATRACE_CALL();
294 ALOGD("BufferHubBuffer::Duplicate: id=%d.", mId);
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700295
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700296 auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700297
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700298 if (!statusOrHandle.ok()) {
299 ALOGE("BufferHubBuffer::Duplicate: Failed to duplicate buffer (id=%d): %s.", mId,
300 statusOrHandle.GetErrorMessage().c_str());
301 }
302 return statusOrHandle;
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700303}
304
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700305} // namespace android