blob: 11849608ba2bafde0cc6ebf0b471e93ffc34e507 [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>
Fan Xucfbe0742018-11-21 15:03:32 -080043#include <ui/BufferHubDefs.h>
Fan Xu069e8382018-11-16 16:28:08 -080044
45using android::base::unique_fd;
Jiwen 'Steve' Cai8f51ec62018-08-07 21:50:51 -070046using android::dvr::BufferTraits;
47using android::dvr::DetachedBufferRPC;
48using android::dvr::NativeHandleWrapper;
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070049
50// TODO(b/112338294): Remove PDX dependencies from libui.
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070051using android::pdx::LocalChannelHandle;
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -070052using android::pdx::LocalHandle;
Jiwen 'Steve' Cai0728fa92018-04-24 19:03:14 -070053using android::pdx::Status;
Jiwen 'Steve' Cai088b3b62018-10-03 18:49:07 -070054using android::pdx::default_transport::ClientChannel;
55using android::pdx::default_transport::ClientChannelFactory;
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -070056
57namespace android {
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -070058
Jiwen 'Steve' Cai9004b8c2018-10-03 18:52:23 -070059namespace {
60
61// TODO(b/112338294): Remove this string literal after refactoring BufferHub
62// to use Binder.
63static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client";
64
Tianyu Jiang7359dc92018-12-13 11:22:28 -080065using BufferHubDefs::AnyClientAcquired;
66using BufferHubDefs::AnyClientGained;
Tianyu Jiang7359dc92018-12-13 11:22:28 -080067using BufferHubDefs::IsClientAcquired;
68using BufferHubDefs::IsClientGained;
69using BufferHubDefs::IsClientPosted;
70using BufferHubDefs::IsClientReleased;
71using BufferHubDefs::kHighBitsMask;
Tianyu Jiangb08b7222018-11-16 17:55:26 -080072
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070073} // namespace
Jiwen 'Steve' Cai9004b8c2018-10-03 18:52:23 -070074
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070075BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(kBufferHubClientPath)) {}
Jiwen 'Steve' Cai088b3b62018-10-03 18:49:07 -070076
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070077BufferHubClient::BufferHubClient(LocalChannelHandle mChannelHandle)
78 : Client(ClientChannel::Create(std::move(mChannelHandle))) {}
Jiwen 'Steve' Cai088b3b62018-10-03 18:49:07 -070079
Jiwen 'Steve' Cai8f51ec62018-08-07 21:50:51 -070080BufferHubClient::~BufferHubClient() {}
81
Jiwen 'Steve' Cai088b3b62018-10-03 18:49:07 -070082bool BufferHubClient::IsValid() const {
Tianyu Jiangb08b7222018-11-16 17:55:26 -080083 return IsConnected() && GetChannelHandle().valid();
Jiwen 'Steve' Cai088b3b62018-10-03 18:49:07 -070084}
85
86LocalChannelHandle BufferHubClient::TakeChannelHandle() {
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070087 if (IsConnected()) {
88 return std::move(GetChannelHandle());
89 } else {
90 return {};
91 }
92}
93
94BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
95 uint32_t format, uint64_t usage, size_t mUserMetadataSize) {
96 ATRACE_CALL();
Tianyu Jiangdf9d91d2018-12-17 10:48:54 -080097 ALOGD("%s: width=%u height=%u layerCount=%u, format=%u usage=%" PRIx64 " mUserMetadataSize=%zu",
98 __FUNCTION__, width, height, layerCount, format, usage, mUserMetadataSize);
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -070099
100 auto status =
101 mClient.InvokeRemoteMethod<DetachedBufferRPC::Create>(width, height, layerCount, format,
102 usage, mUserMetadataSize);
103 if (!status) {
Tianyu Jiangdf9d91d2018-12-17 10:48:54 -0800104 ALOGE("%s: Failed to create detached buffer: %s", __FUNCTION__,
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700105 status.GetErrorMessage().c_str());
106 mClient.Close(-status.error());
107 }
108
109 const int ret = ImportGraphicBuffer();
110 if (ret < 0) {
Tianyu Jiangdf9d91d2018-12-17 10:48:54 -0800111 ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret));
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700112 mClient.Close(ret);
113 }
114}
115
116BufferHubBuffer::BufferHubBuffer(LocalChannelHandle mChannelHandle)
117 : mClient(std::move(mChannelHandle)) {
118 const int ret = ImportGraphicBuffer();
119 if (ret < 0) {
Tianyu Jiangdf9d91d2018-12-17 10:48:54 -0800120 ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret));
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700121 mClient.Close(ret);
122 }
123}
124
125int BufferHubBuffer::ImportGraphicBuffer() {
126 ATRACE_CALL();
127
128 auto status = mClient.InvokeRemoteMethod<DetachedBufferRPC::Import>();
129 if (!status) {
Tianyu Jiangdf9d91d2018-12-17 10:48:54 -0800130 ALOGE("%s: Failed to import GraphicBuffer: %s", __FUNCTION__,
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700131 status.GetErrorMessage().c_str());
132 return -status.error();
133 }
134
135 BufferTraits<LocalHandle> bufferTraits = status.take();
136 if (bufferTraits.id() < 0) {
Tianyu Jiangdf9d91d2018-12-17 10:48:54 -0800137 ALOGE("%s: Received an invalid id!", __FUNCTION__);
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700138 return -EIO;
139 }
140
141 // Stash the buffer id to replace the value in mId.
142 const int bufferId = bufferTraits.id();
143
144 // Import the metadata.
Fan Xu069e8382018-11-16 16:28:08 -0800145 LocalHandle metadataHandle = bufferTraits.take_metadata_handle();
146 unique_fd metadataFd(metadataHandle.Release());
147 mMetadata = BufferHubMetadata::Import(std::move(metadataFd));
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700148
149 if (!mMetadata.IsValid()) {
Tianyu Jiangdf9d91d2018-12-17 10:48:54 -0800150 ALOGE("%s: invalid metadata.", __FUNCTION__);
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700151 return -ENOMEM;
152 }
153
154 if (mMetadata.metadata_size() != bufferTraits.metadata_size()) {
Tianyu Jiangdf9d91d2018-12-17 10:48:54 -0800155 ALOGE("%s: metadata buffer too small: %zu, expected: %" PRIu64 ".", __FUNCTION__,
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700156 mMetadata.metadata_size(), bufferTraits.metadata_size());
157 return -ENOMEM;
158 }
159
160 size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size());
Fan Xucfbe0742018-11-21 15:03:32 -0800161 if (metadataSize < BufferHubDefs::kMetadataHeaderSize) {
Tianyu Jiangdf9d91d2018-12-17 10:48:54 -0800162 ALOGE("%s: metadata too small: %zu", __FUNCTION__, metadataSize);
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700163 return -EINVAL;
164 }
165
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800166 // Populate shortcuts to the atomics in metadata.
167 auto metadata_header = mMetadata.metadata_header();
168 buffer_state_ = &metadata_header->buffer_state;
169 fence_state_ = &metadata_header->fence_state;
170 active_clients_bit_mask_ = &metadata_header->active_clients_bit_mask;
Tianyu Jiang2ceb3202018-12-17 12:58:34 -0800171 // The C++ standard recommends (but does not require) that lock-free atomic operations are
172 // also address-free, that is, suitable for communication between processes using shared
173 // memory.
174 LOG_ALWAYS_FATAL_IF(!std::atomic_is_lock_free(buffer_state_) ||
175 !std::atomic_is_lock_free(fence_state_) ||
176 !std::atomic_is_lock_free(active_clients_bit_mask_),
177 "Atomic variables in ashmen are not lock free.");
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800178
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700179 // Import the buffer: We only need to hold on the native_handle_t here so that
180 // GraphicBuffer instance can be created in future.
181 mBufferHandle = bufferTraits.take_buffer_handle();
182
Jiwen 'Steve' Cai2daf5182018-10-16 00:14:03 -0700183 // Populate buffer desc based on buffer traits.
184 mBufferDesc.width = bufferTraits.width();
185 mBufferDesc.height = bufferTraits.height();
186 mBufferDesc.layers = bufferTraits.layer_count();
187 mBufferDesc.format = bufferTraits.format();
188 mBufferDesc.usage = bufferTraits.usage();
189 mBufferDesc.stride = bufferTraits.stride();
190 mBufferDesc.rfu0 = 0U;
191 mBufferDesc.rfu1 = 0U;
192
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700193 // If all imports succeed, replace the previous buffer and id.
194 mId = bufferId;
Tianyu Jiang7e204b72018-10-26 15:39:18 -0700195 mClientStateMask = bufferTraits.client_state_mask();
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700196
197 // TODO(b/112012161) Set up shared fences.
Tianyu Jiangdf9d91d2018-12-17 10:48:54 -0800198 ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, id(),
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800199 buffer_state_->load(std::memory_order_acquire));
200 return 0;
201}
202
203int BufferHubBuffer::Gain() {
Tianyu Jianga99f9112018-12-13 18:23:07 -0800204 uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800205 if (IsClientGained(current_buffer_state, mClientStateMask)) {
Tianyu Jianga99f9112018-12-13 18:23:07 -0800206 ALOGV("%s: Buffer is already gained by this client %" PRIx32 ".", __FUNCTION__,
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800207 mClientStateMask);
208 return 0;
209 }
210 do {
211 if (AnyClientGained(current_buffer_state & (~mClientStateMask)) ||
212 AnyClientAcquired(current_buffer_state)) {
Tianyu Jianga99f9112018-12-13 18:23:07 -0800213 ALOGE("%s: Buffer is in use, id=%d mClientStateMask=%" PRIx32 " state=%" PRIx32 ".",
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800214 __FUNCTION__, mId, mClientStateMask, current_buffer_state);
215 return -EBUSY;
216 }
217 // Change the buffer state to gained state, whose value happens to be the same as
218 // mClientStateMask.
219 } while (!buffer_state_->compare_exchange_weak(current_buffer_state, mClientStateMask,
220 std::memory_order_acq_rel,
221 std::memory_order_acquire));
222 // TODO(b/119837586): Update fence state and return GPU fence.
223 return 0;
224}
225
226int BufferHubBuffer::Post() {
Tianyu Jianga99f9112018-12-13 18:23:07 -0800227 uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
Tianyu Jiangec97b762019-01-07 17:14:02 -0800228 uint32_t updated_buffer_state = (~mClientStateMask) & kHighBitsMask;
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800229 do {
230 if (!IsClientGained(current_buffer_state, mClientStateMask)) {
231 ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d "
Tianyu Jianga99f9112018-12-13 18:23:07 -0800232 "mClientStateMask=%" PRIx32 " state=%" PRIx32 ".",
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800233 __FUNCTION__, mId, mClientStateMask, current_buffer_state);
234 return -EBUSY;
235 }
236 // Set the producer client buffer state to released, other clients' buffer state to posted.
Tianyu Jiangec97b762019-01-07 17:14:02 -0800237 // Post to all existing and non-existing clients.
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800238 } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
239 std::memory_order_acq_rel,
240 std::memory_order_acquire));
241 // TODO(b/119837586): Update fence state and return GPU fence if needed.
242 return 0;
243}
244
245int BufferHubBuffer::Acquire() {
Tianyu Jianga99f9112018-12-13 18:23:07 -0800246 uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800247 if (IsClientAcquired(current_buffer_state, mClientStateMask)) {
Tianyu Jianga99f9112018-12-13 18:23:07 -0800248 ALOGV("%s: Buffer is already acquired by this client %" PRIx32 ".", __FUNCTION__,
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800249 mClientStateMask);
250 return 0;
251 }
Tianyu Jianga99f9112018-12-13 18:23:07 -0800252 uint32_t updated_buffer_state = 0U;
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800253 do {
254 if (!IsClientPosted(current_buffer_state, mClientStateMask)) {
255 ALOGE("%s: Cannot acquire a buffer that is not in posted state. buffer_id=%d "
Tianyu Jianga99f9112018-12-13 18:23:07 -0800256 "mClientStateMask=%" PRIx32 " state=%" PRIx32 ".",
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800257 __FUNCTION__, mId, mClientStateMask, current_buffer_state);
258 return -EBUSY;
259 }
260 // Change the buffer state for this consumer from posted to acquired.
261 updated_buffer_state = current_buffer_state ^ mClientStateMask;
262 } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
263 std::memory_order_acq_rel,
264 std::memory_order_acquire));
265 // TODO(b/119837586): Update fence state and return GPU fence.
266 return 0;
267}
268
269int BufferHubBuffer::Release() {
Tianyu Jianga99f9112018-12-13 18:23:07 -0800270 uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800271 if (IsClientReleased(current_buffer_state, mClientStateMask)) {
Tianyu Jianga99f9112018-12-13 18:23:07 -0800272 ALOGV("%s: Buffer is already released by this client %" PRIx32 ".", __FUNCTION__,
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800273 mClientStateMask);
274 return 0;
275 }
Tianyu Jianga99f9112018-12-13 18:23:07 -0800276 uint32_t updated_buffer_state = 0U;
Tianyu Jiangb08b7222018-11-16 17:55:26 -0800277 do {
278 updated_buffer_state = current_buffer_state & (~mClientStateMask);
279 } while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
280 std::memory_order_acq_rel,
281 std::memory_order_acquire));
282 // TODO(b/119837586): Update fence state and return GPU fence if needed.
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700283 return 0;
284}
285
286int BufferHubBuffer::Poll(int timeoutMs) {
287 ATRACE_CALL();
288
289 pollfd p = {mClient.event_fd(), POLLIN, 0};
290 return poll(&p, 1, timeoutMs);
291}
292
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700293Status<LocalChannelHandle> BufferHubBuffer::Duplicate() {
294 ATRACE_CALL();
Tianyu Jiangdf9d91d2018-12-17 10:48:54 -0800295 ALOGD("%s: id=%d.", __FUNCTION__, mId);
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700296
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700297 auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700298
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700299 if (!statusOrHandle.ok()) {
Tianyu Jiangdf9d91d2018-12-17 10:48:54 -0800300 ALOGE("%s: Failed to duplicate buffer (id=%d): %s.", __FUNCTION__, mId,
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700301 statusOrHandle.GetErrorMessage().c_str());
302 }
303 return statusOrHandle;
Jiwen 'Steve' Caia8049a22018-03-28 15:14:02 -0700304}
305
Jiwen 'Steve' Caiff675b72018-10-09 18:08:29 -0700306} // namespace android