diff options
author | Corey Tabaka | 2017-09-13 20:02:48 -0500 |
---|---|---|
committer | Jiwen 'Steve' Cai | 2017-10-10 22:39:56 -0500 |
commit | 52ea25cf06cef250ec73052611b48556b3fce4d5 (patch) | |
tree | 6595f49407fbe45702f943d913a1d34bd1910fb8 | |
parent | 35b5114be8da71c69fc8a1ff8fb457c912c0992f (diff) | |
download | frameworks-native-52ea25cf06cef250ec73052611b48556b3fce4d5.tar.gz frameworks-native-52ea25cf06cef250ec73052611b48556b3fce4d5.tar.xz frameworks-native-52ea25cf06cef250ec73052611b48556b3fce4d5.zip |
Add shared memory based buffer metadata
This CLs reduces BufferHub CPU consumption by adding asynchronous
state transition so that out-of-process VR composition can run on 2016
pixel devices smoothly. In addition, this CL addresses a couple corner
cases in the existing bufferhub logic, which fixes various blackscreen
issues.
1/ Tracks buffer transition states (gained, posted, acquired, released)
from the client side via atomic shared memory and adds
PostAsync/AcquireAsync/ReleaseAsync/GainAsync with metadata and
fence support.
2/ Adds dequeue order guarantee for buffers enqueued with
dvrWriteBufferQueuePostBuffer.
3/ Synchronous BuffeHub operations are still supported.
4/ Bump up the bufferhubd's soft limit of open file descriptor.
5/ Handle orphaned consumer in acquired state. This is a corner case
that consumer process goes aways (most likely due to a crash) leaving
buffer stuck in acquired state with inconsistent buffer state.
6/ Fixes a race condition for released buffer to be Gain'ed and
Acquire'd when a new consumer is created in released state.
7/ Improve silent consumer queue efficiency: Silent queues no longer
import buffers or receive signals about new buffers and they are
limited to only spawning other consumers and notifications about
producers hanging up.
8/ Modify PDX/UDS channel event signaling to work around epoll
behavior. PDX UDS uses a combination of an eventfd and an epoll set
to simulate the original PDX transport channel events. An odd
behavior discovered in the kernel implementation of epoll was found
that causes the epoll fd to "unsignal" itself whenever epoll_wait()
is called on it, regardless of whether it should still be
pending. This breaks the edge triggerd behavior in nested epoll sets
that channel events depend on. Since this is unlikely to ever be
fixed in the kernel we work around the behavior by using the epoll
set only as a logical OR of two eventfds and never calling
epoll_wait() on it. When polling is required we use regluar poll()
with the eventfds and data fd to avoid the bad behavior in
epoll_wait().
9/ Keep reading data after PDX hangup signal. UDS will signal hangup
when the other end of the socket closes. However, data could still be
in the kerenl buffer and should be consumed. Fix an issue where the
service misses an impulse sent right before the socket is closed.
Bug: 65455724
Bug: 65458354
Bug: 65458312
Bug: 64027135
Bug: 67424527
Test: libpdx_uds_tests
bufferhub_tests
buffer_hub_queue-test
buffer_hub_queue_producer-test
dvr_api-test
Change-Id: Id07db1f206ccf4e06f7ee3c671193334408971ca
44 files changed, 2072 insertions, 794 deletions
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp index da0ea24da..f32720038 100644 --- a/libs/vr/libbufferhub/Android.bp +++ b/libs/vr/libbufferhub/Android.bp | |||
@@ -37,7 +37,8 @@ sharedLibraries = [ | |||
37 | "libnativewindow" | 37 | "libnativewindow" |
38 | ] | 38 | ] |
39 | 39 | ||
40 | HeaderLibraries = [ | 40 | headerLibraries = [ |
41 | "libdvr_headers", | ||
41 | "libnativebase_headers", | 42 | "libnativebase_headers", |
42 | ] | 43 | ] |
43 | 44 | ||
@@ -45,12 +46,13 @@ cc_library { | |||
45 | srcs: sourceFiles, | 46 | srcs: sourceFiles, |
46 | cflags: [ | 47 | cflags: [ |
47 | "-DLOG_TAG=\"libbufferhub\"", | 48 | "-DLOG_TAG=\"libbufferhub\"", |
48 | "-DTRACE=0" | 49 | "-DTRACE=0", |
50 | "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", | ||
49 | ], | 51 | ], |
50 | export_include_dirs: localIncludeFiles, | 52 | export_include_dirs: localIncludeFiles, |
51 | static_libs: staticLibraries, | 53 | static_libs: staticLibraries, |
52 | shared_libs: sharedLibraries, | 54 | shared_libs: sharedLibraries, |
53 | header_libs: HeaderLibraries, | 55 | header_libs: headerLibraries, |
54 | name: "libbufferhub", | 56 | name: "libbufferhub", |
55 | export_header_lib_headers: [ | 57 | export_header_lib_headers: [ |
56 | "libnativebase_headers", | 58 | "libnativebase_headers", |
@@ -62,6 +64,7 @@ cc_test { | |||
62 | srcs: ["bufferhub_tests.cpp"], | 64 | srcs: ["bufferhub_tests.cpp"], |
63 | static_libs: ["libbufferhub"] + staticLibraries, | 65 | static_libs: ["libbufferhub"] + staticLibraries, |
64 | shared_libs: sharedLibraries, | 66 | shared_libs: sharedLibraries, |
67 | header_libs: headerLibraries, | ||
65 | name: "bufferhub_tests", | 68 | name: "bufferhub_tests", |
66 | } | 69 | } |
67 | 70 | ||
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp index b9a53b0ce..97341b147 100644 --- a/libs/vr/libbufferhub/buffer_hub_client.cpp +++ b/libs/vr/libbufferhub/buffer_hub_client.cpp | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | #include <log/log.h> | 3 | #include <log/log.h> |
4 | #include <poll.h> | 4 | #include <poll.h> |
5 | #define ATRACE_TAG ATRACE_TAG_GRAPHICS | 5 | #include <sys/epoll.h> |
6 | #include <utils/Trace.h> | 6 | #include <utils/Trace.h> |
7 | 7 | ||
8 | #include <mutex> | 8 | #include <mutex> |
@@ -12,9 +12,8 @@ | |||
12 | 12 | ||
13 | #include "include/private/dvr/bufferhub_rpc.h" | 13 | #include "include/private/dvr/bufferhub_rpc.h" |
14 | 14 | ||
15 | using android::pdx::LocalHandle; | ||
16 | using android::pdx::LocalChannelHandle; | 15 | using android::pdx::LocalChannelHandle; |
17 | using android::pdx::rpc::WrapBuffer; | 16 | using android::pdx::LocalHandle; |
18 | using android::pdx::Status; | 17 | using android::pdx::Status; |
19 | 18 | ||
20 | namespace android { | 19 | namespace android { |
@@ -29,7 +28,11 @@ BufferHubBuffer::BufferHubBuffer(const std::string& endpoint_path) | |||
29 | endpoint_path)}, | 28 | endpoint_path)}, |
30 | id_(-1) {} | 29 | id_(-1) {} |
31 | 30 | ||
32 | BufferHubBuffer::~BufferHubBuffer() {} | 31 | BufferHubBuffer::~BufferHubBuffer() { |
32 | if (metadata_header_ != nullptr) { | ||
33 | metadata_buffer_.Unlock(); | ||
34 | } | ||
35 | } | ||
33 | 36 | ||
34 | Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() { | 37 | Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() { |
35 | Status<LocalChannelHandle> status = | 38 | Status<LocalChannelHandle> status = |
@@ -43,7 +46,7 @@ Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() { | |||
43 | int BufferHubBuffer::ImportBuffer() { | 46 | int BufferHubBuffer::ImportBuffer() { |
44 | ATRACE_NAME("BufferHubBuffer::ImportBuffer"); | 47 | ATRACE_NAME("BufferHubBuffer::ImportBuffer"); |
45 | 48 | ||
46 | Status<NativeBufferHandle<LocalHandle>> status = | 49 | Status<BufferDescription<LocalHandle>> status = |
47 | InvokeRemoteMethod<BufferHubRPC::GetBuffer>(); | 50 | InvokeRemoteMethod<BufferHubRPC::GetBuffer>(); |
48 | if (!status) { | 51 | if (!status) { |
49 | ALOGE("BufferHubBuffer::ImportBuffer: Failed to get buffer: %s", | 52 | ALOGE("BufferHubBuffer::ImportBuffer: Failed to get buffer: %s", |
@@ -54,24 +57,135 @@ int BufferHubBuffer::ImportBuffer() { | |||
54 | return -EIO; | 57 | return -EIO; |
55 | } | 58 | } |
56 | 59 | ||
57 | auto buffer_handle = status.take(); | 60 | auto buffer_desc = status.take(); |
58 | 61 | ||
59 | // Stash the buffer id to replace the value in id_. | 62 | // Stash the buffer id to replace the value in id_. |
60 | const int new_id = buffer_handle.id(); | 63 | const int new_id = buffer_desc.id(); |
61 | 64 | ||
62 | // Import the buffer. | 65 | // Import the buffer. |
63 | IonBuffer ion_buffer; | 66 | IonBuffer ion_buffer; |
64 | ALOGD_IF( | 67 | ALOGD_IF(TRACE, "BufferHubBuffer::ImportBuffer: id=%d.", buffer_desc.id()); |
65 | TRACE, "BufferHubBuffer::ImportBuffer: id=%d FdCount=%zu IntCount=%zu", | ||
66 | buffer_handle.id(), buffer_handle.FdCount(), buffer_handle.IntCount()); | ||
67 | 68 | ||
68 | const int ret = buffer_handle.Import(&ion_buffer); | 69 | if (const int ret = buffer_desc.ImportBuffer(&ion_buffer)) |
69 | if (ret < 0) | ||
70 | return ret; | 70 | return ret; |
71 | 71 | ||
72 | // If the import succeeds, replace the previous buffer and id. | 72 | // Import the metadata. |
73 | IonBuffer metadata_buffer; | ||
74 | if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) { | ||
75 | ALOGE("Failed to import metadata buffer, error=%d", ret); | ||
76 | return ret; | ||
77 | } | ||
78 | size_t metadata_buf_size = metadata_buffer.width(); | ||
79 | if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) { | ||
80 | ALOGE("BufferHubBuffer::ImportBuffer: metadata buffer too small: %zu", | ||
81 | metadata_buf_size); | ||
82 | return -ENOMEM; | ||
83 | } | ||
84 | |||
85 | // If all imports succee, replace the previous buffer and id. | ||
73 | buffer_ = std::move(ion_buffer); | 86 | buffer_ = std::move(ion_buffer); |
87 | metadata_buffer_ = std::move(metadata_buffer); | ||
88 | metadata_buf_size_ = metadata_buf_size; | ||
89 | user_metadata_size_ = metadata_buf_size_ - BufferHubDefs::kMetadataHeaderSize; | ||
90 | |||
91 | void* metadata_ptr = nullptr; | ||
92 | if (const int ret = | ||
93 | metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0, | ||
94 | /*y=*/0, metadata_buf_size_, | ||
95 | /*height=*/1, &metadata_ptr)) { | ||
96 | ALOGE("BufferHubBuffer::ImportBuffer: Failed to lock metadata."); | ||
97 | return ret; | ||
98 | } | ||
99 | |||
100 | // Set up shared fences. | ||
101 | shared_acquire_fence_ = buffer_desc.take_acquire_fence(); | ||
102 | shared_release_fence_ = buffer_desc.take_release_fence(); | ||
103 | if (!shared_acquire_fence_ || !shared_release_fence_) { | ||
104 | ALOGE("BufferHubBuffer::ImportBuffer: Failed to import shared fences."); | ||
105 | return -EIO; | ||
106 | } | ||
107 | |||
108 | metadata_header_ = | ||
109 | reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr); | ||
110 | if (user_metadata_size_) { | ||
111 | user_metadata_ptr_ = | ||
112 | reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(metadata_ptr) + | ||
113 | BufferHubDefs::kMetadataHeaderSize); | ||
114 | } else { | ||
115 | user_metadata_ptr_ = nullptr; | ||
116 | } | ||
117 | |||
74 | id_ = new_id; | 118 | id_ = new_id; |
119 | buffer_state_bit_ = buffer_desc.buffer_state_bit(); | ||
120 | |||
121 | // Note that here the buffer state is mapped from shared memory as an atomic | ||
122 | // object. The std::atomic's constructor will not be called so that the | ||
123 | // original value stored in the memory region will be preserved. | ||
124 | buffer_state_ = &metadata_header_->buffer_state; | ||
125 | ALOGD_IF(TRACE, | ||
126 | "BufferHubBuffer::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".", | ||
127 | id(), buffer_state_->load()); | ||
128 | fence_state_ = &metadata_header_->fence_state; | ||
129 | ALOGD_IF(TRACE, | ||
130 | "BufferHubBuffer::ImportBuffer: id=%d, fence_state=%" PRIx64 ".", | ||
131 | id(), fence_state_->load()); | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | inline int BufferHubBuffer::CheckMetadata(size_t user_metadata_size) const { | ||
137 | if (user_metadata_size && !user_metadata_ptr_) { | ||
138 | ALOGE("BufferHubBuffer::CheckMetadata: doesn't support custom metadata."); | ||
139 | return -EINVAL; | ||
140 | } | ||
141 | if (user_metadata_size > user_metadata_size_) { | ||
142 | ALOGE("BufferHubBuffer::CheckMetadata: too big: %zu, maximum: %zu.", | ||
143 | user_metadata_size, user_metadata_size_); | ||
144 | return -E2BIG; | ||
145 | } | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | int BufferHubBuffer::UpdateSharedFence(const LocalHandle& new_fence, | ||
150 | const LocalHandle& shared_fence) { | ||
151 | if (pending_fence_fd_.Get() != new_fence.Get()) { | ||
152 | // First, replace the old fd if there was already one. Skipping if the new | ||
153 | // one is the same as the old. | ||
154 | if (pending_fence_fd_.IsValid()) { | ||
155 | const int ret = epoll_ctl(shared_fence.Get(), EPOLL_CTL_DEL, | ||
156 | pending_fence_fd_.Get(), nullptr); | ||
157 | ALOGW_IF(ret, | ||
158 | "BufferHubBuffer::UpdateSharedFence: failed to remove old fence " | ||
159 | "fd from epoll set, error: %s.", | ||
160 | strerror(errno)); | ||
161 | } | ||
162 | |||
163 | if (new_fence.IsValid()) { | ||
164 | // If ready fence is valid, we put that into the epoll set. | ||
165 | epoll_event event; | ||
166 | event.events = EPOLLIN; | ||
167 | event.data.u64 = buffer_state_bit(); | ||
168 | pending_fence_fd_ = new_fence.Duplicate(); | ||
169 | if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(), | ||
170 | &event) < 0) { | ||
171 | const int error = errno; | ||
172 | ALOGE( | ||
173 | "BufferHubBuffer::UpdateSharedFence: failed to add new fence fd " | ||
174 | "into epoll set, error: %s.", | ||
175 | strerror(error)); | ||
176 | return -error; | ||
177 | } | ||
178 | // Set bit in fence state to indicate that there is a fence from this | ||
179 | // producer or consumer. | ||
180 | fence_state_->fetch_or(buffer_state_bit()); | ||
181 | } else { | ||
182 | // Unset bit in fence state to indicate that there is no fence, so that | ||
183 | // when consumer to acquire or producer to acquire, it knows no need to | ||
184 | // check fence for this buffer. | ||
185 | fence_state_->fetch_and(~buffer_state_bit()); | ||
186 | } | ||
187 | } | ||
188 | |||
75 | return 0; | 189 | return 0; |
76 | } | 190 | } |
77 | 191 | ||
@@ -131,31 +245,144 @@ std::unique_ptr<BufferConsumer> BufferConsumer::Import( | |||
131 | : LocalChannelHandle{nullptr, -status.error()}); | 245 | : LocalChannelHandle{nullptr, -status.error()}); |
132 | } | 246 | } |
133 | 247 | ||
248 | int BufferConsumer::LocalAcquire(DvrNativeBufferMetadata* out_meta, | ||
249 | LocalHandle* out_fence) { | ||
250 | if (!out_meta) | ||
251 | return -EINVAL; | ||
252 | |||
253 | // Only check producer bit and this consumer buffer's particular consumer bit. | ||
254 | // The buffer is can be acquired iff: 1) producer bit is set; 2) consumer bit | ||
255 | // is not set. | ||
256 | uint64_t buffer_state = buffer_state_->load(); | ||
257 | if (!BufferHubDefs::IsBufferPosted(buffer_state, buffer_state_bit())) { | ||
258 | ALOGE("BufferConsumer::LocalAcquire: not posted, id=%d state=%" PRIx64 | ||
259 | " buffer_state_bit=%" PRIx64 ".", | ||
260 | id(), buffer_state, buffer_state_bit()); | ||
261 | return -EBUSY; | ||
262 | } | ||
263 | |||
264 | // Copy the canonical metadata. | ||
265 | void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata); | ||
266 | memcpy(out_meta, metadata_ptr, sizeof(DvrNativeBufferMetadata)); | ||
267 | // Fill in the user_metadata_ptr in address space of the local process. | ||
268 | if (out_meta->user_metadata_size) { | ||
269 | out_meta->user_metadata_ptr = | ||
270 | reinterpret_cast<uint64_t>(user_metadata_ptr_); | ||
271 | } else { | ||
272 | out_meta->user_metadata_ptr = 0; | ||
273 | } | ||
274 | |||
275 | uint64_t fence_state = fence_state_->load(); | ||
276 | // If there is an acquire fence from producer, we need to return it. | ||
277 | if (fence_state & BufferHubDefs::kProducerStateBit) { | ||
278 | *out_fence = shared_acquire_fence_.Duplicate(); | ||
279 | } | ||
280 | |||
281 | // Set the consumer bit unique to this consumer. | ||
282 | BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, buffer_state_bit()); | ||
283 | return 0; | ||
284 | } | ||
285 | |||
134 | int BufferConsumer::Acquire(LocalHandle* ready_fence) { | 286 | int BufferConsumer::Acquire(LocalHandle* ready_fence) { |
135 | return Acquire(ready_fence, nullptr, 0); | 287 | return Acquire(ready_fence, nullptr, 0); |
136 | } | 288 | } |
137 | 289 | ||
138 | int BufferConsumer::Acquire(LocalHandle* ready_fence, void* meta, | 290 | int BufferConsumer::Acquire(LocalHandle* ready_fence, void* meta, |
139 | size_t meta_size_bytes) { | 291 | size_t user_metadata_size) { |
140 | ATRACE_NAME("BufferConsumer::Acquire"); | 292 | ATRACE_NAME("BufferConsumer::Acquire"); |
141 | LocalFence fence; | 293 | |
142 | auto return_value = | 294 | if (const int error = CheckMetadata(user_metadata_size)) |
143 | std::make_pair(std::ref(fence), WrapBuffer(meta, meta_size_bytes)); | 295 | return error; |
144 | auto status = InvokeRemoteMethodInPlace<BufferHubRPC::ConsumerAcquire>( | 296 | |
145 | &return_value, meta_size_bytes); | 297 | DvrNativeBufferMetadata canonical_meta; |
146 | if (status && ready_fence) | 298 | if (const int error = LocalAcquire(&canonical_meta, ready_fence)) |
147 | *ready_fence = fence.take(); | 299 | return error; |
148 | return status ? 0 : -status.error(); | 300 | |
301 | if (meta && user_metadata_size) { | ||
302 | void* metadata_src = | ||
303 | reinterpret_cast<void*>(canonical_meta.user_metadata_ptr); | ||
304 | if (metadata_src) { | ||
305 | memcpy(meta, metadata_src, user_metadata_size); | ||
306 | } else { | ||
307 | ALOGW("BufferConsumer::Acquire: no user-defined metadata."); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerAcquire>(); | ||
312 | if (!status) | ||
313 | return -status.error(); | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | int BufferConsumer::AcquireAsync(DvrNativeBufferMetadata* out_meta, | ||
318 | LocalHandle* out_fence) { | ||
319 | ATRACE_NAME("BufferConsumer::AcquireAsync"); | ||
320 | |||
321 | if (const int error = LocalAcquire(out_meta, out_fence)) | ||
322 | return error; | ||
323 | |||
324 | auto status = SendImpulse(BufferHubRPC::ConsumerAcquire::Opcode); | ||
325 | if (!status) | ||
326 | return -status.error(); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | int BufferConsumer::LocalRelease(const DvrNativeBufferMetadata* meta, | ||
331 | const LocalHandle& release_fence) { | ||
332 | if (const int error = CheckMetadata(meta->user_metadata_size)) | ||
333 | return error; | ||
334 | |||
335 | // Check invalid state transition. | ||
336 | uint64_t buffer_state = buffer_state_->load(); | ||
337 | if (!BufferHubDefs::IsBufferAcquired(buffer_state)) { | ||
338 | ALOGE("BufferConsumer::LocalRelease: not acquired id=%d state=%" PRIx64 ".", | ||
339 | id(), buffer_state); | ||
340 | return -EBUSY; | ||
341 | } | ||
342 | |||
343 | // On release, only the user requested metadata is copied back into the shared | ||
344 | // memory for metadata. Since there are multiple consumers, it doesn't make | ||
345 | // sense to send the canonical metadata back to the producer. However, one of | ||
346 | // the consumer can still choose to write up to user_metadata_size bytes of | ||
347 | // data into user_metadata_ptr. | ||
348 | if (meta->user_metadata_ptr && meta->user_metadata_size) { | ||
349 | void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr); | ||
350 | memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size); | ||
351 | } | ||
352 | |||
353 | // Send out the release fence through the shared epoll fd. Note that during | ||
354 | // releasing the producer is not expected to be polling on the fence. | ||
355 | if (const int error = UpdateSharedFence(release_fence, shared_release_fence_)) | ||
356 | return error; | ||
357 | |||
358 | // For release operation, the client don't need to change the state as it's | ||
359 | // bufferhubd's job to flip the produer bit once all consumers are released. | ||
360 | return 0; | ||
149 | } | 361 | } |
150 | 362 | ||
151 | int BufferConsumer::Release(const LocalHandle& release_fence) { | 363 | int BufferConsumer::Release(const LocalHandle& release_fence) { |
152 | ATRACE_NAME("BufferConsumer::Release"); | 364 | ATRACE_NAME("BufferConsumer::Release"); |
365 | |||
366 | DvrNativeBufferMetadata meta; | ||
367 | if (const int error = LocalRelease(&meta, release_fence)) | ||
368 | return error; | ||
369 | |||
153 | return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ConsumerRelease>( | 370 | return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ConsumerRelease>( |
154 | BorrowedFence(release_fence.Borrow()))); | 371 | BorrowedFence(release_fence.Borrow()))); |
155 | } | 372 | } |
156 | 373 | ||
157 | int BufferConsumer::ReleaseAsync() { | 374 | int BufferConsumer::ReleaseAsync() { |
375 | DvrNativeBufferMetadata meta; | ||
376 | return ReleaseAsync(&meta, LocalHandle()); | ||
377 | } | ||
378 | |||
379 | int BufferConsumer::ReleaseAsync(const DvrNativeBufferMetadata* meta, | ||
380 | const LocalHandle& release_fence) { | ||
158 | ATRACE_NAME("BufferConsumer::ReleaseAsync"); | 381 | ATRACE_NAME("BufferConsumer::ReleaseAsync"); |
382 | |||
383 | if (const int error = LocalRelease(meta, release_fence)) | ||
384 | return error; | ||
385 | |||
159 | return ReturnStatusOrError( | 386 | return ReturnStatusOrError( |
160 | SendImpulse(BufferHubRPC::ConsumerRelease::Opcode)); | 387 | SendImpulse(BufferHubRPC::ConsumerRelease::Opcode)); |
161 | } | 388 | } |
@@ -168,24 +395,25 @@ int BufferConsumer::SetIgnore(bool ignore) { | |||
168 | } | 395 | } |
169 | 396 | ||
170 | BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, | 397 | BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, |
171 | uint32_t usage, size_t metadata_size) | 398 | uint32_t usage, size_t user_metadata_size) |
172 | : BufferProducer(width, height, format, usage, usage, metadata_size) {} | 399 | : BufferProducer(width, height, format, usage, usage, user_metadata_size) {} |
173 | 400 | ||
174 | BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, | 401 | BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, |
175 | uint64_t producer_usage, uint64_t consumer_usage, | 402 | uint64_t producer_usage, uint64_t consumer_usage, |
176 | size_t metadata_size) | 403 | size_t user_metadata_size) |
177 | : BASE(BufferHubRPC::kClientPath) { | 404 | : BASE(BufferHubRPC::kClientPath) { |
178 | ATRACE_NAME("BufferProducer::BufferProducer"); | 405 | ATRACE_NAME("BufferProducer::BufferProducer"); |
179 | ALOGD_IF(TRACE, | 406 | ALOGD_IF(TRACE, |
180 | "BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u " | 407 | "BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u " |
181 | "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 | 408 | "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 |
182 | " metadata_size=%zu", | 409 | " user_metadata_size=%zu", |
183 | event_fd(), width, height, format, producer_usage, consumer_usage, | 410 | event_fd(), width, height, format, producer_usage, consumer_usage, |
184 | metadata_size); | 411 | user_metadata_size); |
185 | 412 | ||
186 | // (b/37881101) Deprecate producer/consumer usage | 413 | // (b/37881101) Deprecate producer/consumer usage |
187 | auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( | 414 | auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( |
188 | width, height, format, (producer_usage | consumer_usage), metadata_size); | 415 | width, height, format, (producer_usage | consumer_usage), |
416 | user_metadata_size); | ||
189 | if (!status) { | 417 | if (!status) { |
190 | ALOGE( | 418 | ALOGE( |
191 | "BufferProducer::BufferProducer: Failed to create producer buffer: %s", | 419 | "BufferProducer::BufferProducer: Failed to create producer buffer: %s", |
@@ -206,27 +434,28 @@ BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, | |||
206 | BufferProducer::BufferProducer(const std::string& name, int user_id, | 434 | BufferProducer::BufferProducer(const std::string& name, int user_id, |
207 | int group_id, uint32_t width, uint32_t height, | 435 | int group_id, uint32_t width, uint32_t height, |
208 | uint32_t format, uint32_t usage, | 436 | uint32_t format, uint32_t usage, |
209 | size_t meta_size_bytes) | 437 | size_t user_metadata_size) |
210 | : BufferProducer(name, user_id, group_id, width, height, format, usage, | 438 | : BufferProducer(name, user_id, group_id, width, height, format, usage, |
211 | usage, meta_size_bytes) {} | 439 | usage, user_metadata_size) {} |
212 | 440 | ||
213 | BufferProducer::BufferProducer(const std::string& name, int user_id, | 441 | BufferProducer::BufferProducer(const std::string& name, int user_id, |
214 | int group_id, uint32_t width, uint32_t height, | 442 | int group_id, uint32_t width, uint32_t height, |
215 | uint32_t format, uint64_t producer_usage, | 443 | uint32_t format, uint64_t producer_usage, |
216 | uint64_t consumer_usage, size_t meta_size_bytes) | 444 | uint64_t consumer_usage, |
445 | size_t user_metadata_size) | ||
217 | : BASE(BufferHubRPC::kClientPath) { | 446 | : BASE(BufferHubRPC::kClientPath) { |
218 | ATRACE_NAME("BufferProducer::BufferProducer"); | 447 | ATRACE_NAME("BufferProducer::BufferProducer"); |
219 | ALOGD_IF(TRACE, | 448 | ALOGD_IF(TRACE, |
220 | "BufferProducer::BufferProducer: fd=%d name=%s user_id=%d " | 449 | "BufferProducer::BufferProducer: fd=%d name=%s user_id=%d " |
221 | "group_id=%d width=%u height=%u format=%u producer_usage=%" PRIx64 | 450 | "group_id=%d width=%u height=%u format=%u producer_usage=%" PRIx64 |
222 | " consumer_usage=%" PRIx64 " meta_size_bytes=%zu", | 451 | " consumer_usage=%" PRIx64 " user_metadata_size=%zu", |
223 | event_fd(), name.c_str(), user_id, group_id, width, height, format, | 452 | event_fd(), name.c_str(), user_id, group_id, width, height, format, |
224 | producer_usage, consumer_usage, meta_size_bytes); | 453 | producer_usage, consumer_usage, user_metadata_size); |
225 | 454 | ||
226 | // (b/37881101) Deprecate producer/consumer usage | 455 | // (b/37881101) Deprecate producer/consumer usage |
227 | auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( | 456 | auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( |
228 | name, user_id, group_id, width, height, format, | 457 | name, user_id, group_id, width, height, format, |
229 | (producer_usage | consumer_usage), meta_size_bytes); | 458 | (producer_usage | consumer_usage), user_metadata_size); |
230 | if (!status) { | 459 | if (!status) { |
231 | ALOGE( | 460 | ALOGE( |
232 | "BufferProducer::BufferProducer: Failed to create/get persistent " | 461 | "BufferProducer::BufferProducer: Failed to create/get persistent " |
@@ -260,12 +489,12 @@ BufferProducer::BufferProducer(uint64_t producer_usage, uint64_t consumer_usage, | |||
260 | const int width = static_cast<int>(size); | 489 | const int width = static_cast<int>(size); |
261 | const int height = 1; | 490 | const int height = 1; |
262 | const int format = HAL_PIXEL_FORMAT_BLOB; | 491 | const int format = HAL_PIXEL_FORMAT_BLOB; |
263 | const size_t meta_size_bytes = 0; | 492 | const size_t user_metadata_size = 0; |
264 | 493 | ||
265 | // (b/37881101) Deprecate producer/consumer usage | 494 | // (b/37881101) Deprecate producer/consumer usage |
266 | auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( | 495 | auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( |
267 | width, height, format, (producer_usage | consumer_usage), | 496 | width, height, format, (producer_usage | consumer_usage), |
268 | meta_size_bytes); | 497 | user_metadata_size); |
269 | if (!status) { | 498 | if (!status) { |
270 | ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s", | 499 | ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s", |
271 | status.GetErrorMessage().c_str()); | 500 | status.GetErrorMessage().c_str()); |
@@ -299,12 +528,12 @@ BufferProducer::BufferProducer(const std::string& name, int user_id, | |||
299 | const int width = static_cast<int>(size); | 528 | const int width = static_cast<int>(size); |
300 | const int height = 1; | 529 | const int height = 1; |
301 | const int format = HAL_PIXEL_FORMAT_BLOB; | 530 | const int format = HAL_PIXEL_FORMAT_BLOB; |
302 | const size_t meta_size_bytes = 0; | 531 | const size_t user_metadata_size = 0; |
303 | 532 | ||
304 | // (b/37881101) Deprecate producer/consumer usage | 533 | // (b/37881101) Deprecate producer/consumer usage |
305 | auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( | 534 | auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( |
306 | name, user_id, group_id, width, height, format, | 535 | name, user_id, group_id, width, height, format, |
307 | (producer_usage | consumer_usage), meta_size_bytes); | 536 | (producer_usage | consumer_usage), user_metadata_size); |
308 | if (!status) { | 537 | if (!status) { |
309 | ALOGE( | 538 | ALOGE( |
310 | "BufferProducer::BufferProducer: Failed to create persistent " | 539 | "BufferProducer::BufferProducer: Failed to create persistent " |
@@ -360,28 +589,141 @@ BufferProducer::BufferProducer(LocalChannelHandle channel) | |||
360 | } | 589 | } |
361 | } | 590 | } |
362 | 591 | ||
592 | int BufferProducer::LocalPost(const DvrNativeBufferMetadata* meta, | ||
593 | const LocalHandle& ready_fence) { | ||
594 | if (const int error = CheckMetadata(meta->user_metadata_size)) | ||
595 | return error; | ||
596 | |||
597 | // Check invalid state transition. | ||
598 | uint64_t buffer_state = buffer_state_->load(); | ||
599 | if (!BufferHubDefs::IsBufferGained(buffer_state)) { | ||
600 | ALOGE("BufferProducer::LocalPost: not gained, id=%d state=%" PRIx64 ".", | ||
601 | id(), buffer_state); | ||
602 | return -EBUSY; | ||
603 | } | ||
604 | |||
605 | // Copy the canonical metadata. | ||
606 | void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata); | ||
607 | memcpy(metadata_ptr, meta, sizeof(DvrNativeBufferMetadata)); | ||
608 | // Copy extra user requested metadata. | ||
609 | if (meta->user_metadata_ptr && meta->user_metadata_size) { | ||
610 | void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr); | ||
611 | memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size); | ||
612 | } | ||
613 | |||
614 | // Send out the acquire fence through the shared epoll fd. Note that during | ||
615 | // posting no consumer is not expected to be polling on the fence. | ||
616 | if (const int error = UpdateSharedFence(ready_fence, shared_acquire_fence_)) | ||
617 | return error; | ||
618 | |||
619 | // Set the producer bit atomically to transit into posted state. | ||
620 | BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, | ||
621 | BufferHubDefs::kProducerStateBit); | ||
622 | return 0; | ||
623 | } | ||
624 | |||
363 | int BufferProducer::Post(const LocalHandle& ready_fence, const void* meta, | 625 | int BufferProducer::Post(const LocalHandle& ready_fence, const void* meta, |
364 | size_t meta_size_bytes) { | 626 | size_t user_metadata_size) { |
365 | ATRACE_NAME("BufferProducer::Post"); | 627 | ATRACE_NAME("BufferProducer::Post"); |
628 | |||
629 | // Populate cononical metadata for posting. | ||
630 | DvrNativeBufferMetadata canonical_meta; | ||
631 | canonical_meta.user_metadata_ptr = reinterpret_cast<uint64_t>(meta); | ||
632 | canonical_meta.user_metadata_size = user_metadata_size; | ||
633 | |||
634 | if (const int error = LocalPost(&canonical_meta, ready_fence)) | ||
635 | return error; | ||
636 | |||
366 | return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ProducerPost>( | 637 | return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ProducerPost>( |
367 | BorrowedFence(ready_fence.Borrow()), WrapBuffer(meta, meta_size_bytes))); | 638 | BorrowedFence(ready_fence.Borrow()))); |
639 | } | ||
640 | |||
641 | int BufferProducer::PostAsync(const DvrNativeBufferMetadata* meta, | ||
642 | const LocalHandle& ready_fence) { | ||
643 | ATRACE_NAME("BufferProducer::PostAsync"); | ||
644 | |||
645 | if (const int error = LocalPost(meta, ready_fence)) | ||
646 | return error; | ||
647 | |||
648 | return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerPost::Opcode)); | ||
649 | } | ||
650 | |||
651 | int BufferProducer::LocalGain(DvrNativeBufferMetadata* out_meta, | ||
652 | LocalHandle* out_fence) { | ||
653 | uint64_t buffer_state = buffer_state_->load(); | ||
654 | ALOGD_IF(TRACE, "BufferProducer::LocalGain: buffer=%d, state=%" PRIx64 ".", | ||
655 | id(), buffer_state); | ||
656 | |||
657 | if (!out_meta) | ||
658 | return -EINVAL; | ||
659 | |||
660 | if (!BufferHubDefs::IsBufferReleased(buffer_state)) { | ||
661 | if (BufferHubDefs::IsBufferGained(buffer_state)) { | ||
662 | // We don't want to log error when gaining a newly allocated | ||
663 | // buffer. | ||
664 | ALOGI("BufferProducer::LocalGain: already gained id=%d.", id()); | ||
665 | return -EALREADY; | ||
666 | } | ||
667 | ALOGE("BufferProducer::LocalGain: not released id=%d state=%" PRIx64 ".", | ||
668 | id(), buffer_state); | ||
669 | return -EBUSY; | ||
670 | } | ||
671 | |||
672 | // Canonical metadata is undefined on Gain. Except for user_metadata and | ||
673 | // release_fence_mask. Fill in the user_metadata_ptr in address space of the | ||
674 | // local process. | ||
675 | if (metadata_header_->metadata.user_metadata_size && user_metadata_ptr_) { | ||
676 | out_meta->user_metadata_size = | ||
677 | metadata_header_->metadata.user_metadata_size; | ||
678 | out_meta->user_metadata_ptr = | ||
679 | reinterpret_cast<uint64_t>(user_metadata_ptr_); | ||
680 | } else { | ||
681 | out_meta->user_metadata_size = 0; | ||
682 | out_meta->user_metadata_ptr = 0; | ||
683 | } | ||
684 | |||
685 | uint64_t fence_state = fence_state_->load(); | ||
686 | // If there is an release fence from consumer, we need to return it. | ||
687 | if (fence_state & BufferHubDefs::kConsumerStateMask) { | ||
688 | *out_fence = shared_release_fence_.Duplicate(); | ||
689 | out_meta->release_fence_mask = | ||
690 | fence_state & BufferHubDefs::kConsumerStateMask; | ||
691 | } | ||
692 | |||
693 | // Clear out all bits and the buffer is now back to gained state. | ||
694 | buffer_state_->store(0ULL); | ||
695 | return 0; | ||
368 | } | 696 | } |
369 | 697 | ||
370 | int BufferProducer::Gain(LocalHandle* release_fence) { | 698 | int BufferProducer::Gain(LocalHandle* release_fence) { |
371 | ATRACE_NAME("BufferProducer::Gain"); | 699 | ATRACE_NAME("BufferProducer::Gain"); |
700 | |||
701 | DvrNativeBufferMetadata meta; | ||
702 | if (const int error = LocalGain(&meta, release_fence)) | ||
703 | return error; | ||
704 | |||
372 | auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>(); | 705 | auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>(); |
373 | if (!status) | 706 | if (!status) |
374 | return -status.error(); | 707 | return -status.error(); |
375 | if (release_fence) | ||
376 | *release_fence = status.take().take(); | ||
377 | return 0; | 708 | return 0; |
378 | } | 709 | } |
379 | 710 | ||
380 | int BufferProducer::GainAsync() { | 711 | int BufferProducer::GainAsync(DvrNativeBufferMetadata* out_meta, |
712 | LocalHandle* release_fence) { | ||
381 | ATRACE_NAME("BufferProducer::GainAsync"); | 713 | ATRACE_NAME("BufferProducer::GainAsync"); |
714 | |||
715 | if (const int error = LocalGain(out_meta, release_fence)) | ||
716 | return error; | ||
717 | |||
382 | return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode)); | 718 | return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode)); |
383 | } | 719 | } |
384 | 720 | ||
721 | int BufferProducer::GainAsync() { | ||
722 | DvrNativeBufferMetadata meta; | ||
723 | LocalHandle fence; | ||
724 | return GainAsync(&meta, &fence); | ||
725 | } | ||
726 | |||
385 | std::unique_ptr<BufferProducer> BufferProducer::Import( | 727 | std::unique_ptr<BufferProducer> BufferProducer::Import( |
386 | LocalChannelHandle channel) { | 728 | LocalChannelHandle channel) { |
387 | ALOGD_IF(TRACE, "BufferProducer::Import: channel=%d", channel.value()); | 729 | ALOGD_IF(TRACE, "BufferProducer::Import: channel=%d", channel.value()); |
diff --git a/libs/vr/libbufferhub/bufferhub_tests.cpp b/libs/vr/libbufferhub/bufferhub_tests.cpp index 1daa5d62d..c4b9a8c88 100644 --- a/libs/vr/libbufferhub/bufferhub_tests.cpp +++ b/libs/vr/libbufferhub/bufferhub_tests.cpp | |||
@@ -1,5 +1,9 @@ | |||
1 | #include <gtest/gtest.h> | 1 | #include <gtest/gtest.h> |
2 | #include <poll.h> | ||
2 | #include <private/dvr/buffer_hub_client.h> | 3 | #include <private/dvr/buffer_hub_client.h> |
4 | #include <private/dvr/bufferhub_rpc.h> | ||
5 | #include <sys/epoll.h> | ||
6 | #include <sys/eventfd.h> | ||
3 | 7 | ||
4 | #include <mutex> | 8 | #include <mutex> |
5 | #include <thread> | 9 | #include <thread> |
@@ -13,8 +17,10 @@ | |||
13 | return result; \ | 17 | return result; \ |
14 | })() | 18 | })() |
15 | 19 | ||
16 | using android::dvr::BufferProducer; | ||
17 | using android::dvr::BufferConsumer; | 20 | using android::dvr::BufferConsumer; |
21 | using android::dvr::BufferHubDefs::kConsumerStateMask; | ||
22 | using android::dvr::BufferHubDefs::kProducerStateBit; | ||
23 | using android::dvr::BufferProducer; | ||
18 | using android::pdx::LocalHandle; | 24 | using android::pdx::LocalHandle; |
19 | 25 | ||
20 | const int kWidth = 640; | 26 | const int kWidth = 640; |
@@ -37,29 +43,149 @@ TEST_F(LibBufferHubTest, TestBasicUsage) { | |||
37 | BufferConsumer::Import(c->CreateConsumer()); | 43 | BufferConsumer::Import(c->CreateConsumer()); |
38 | ASSERT_TRUE(c2.get() != nullptr); | 44 | ASSERT_TRUE(c2.get() != nullptr); |
39 | 45 | ||
46 | // Producer state mask is unique, i.e. 1. | ||
47 | EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit); | ||
48 | // Consumer state mask cannot have producer bit on. | ||
49 | EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0); | ||
50 | // Consumer state mask must be a single, i.e. power of 2. | ||
51 | EXPECT_NE(c->buffer_state_bit(), 0); | ||
52 | EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0); | ||
53 | // Consumer state mask cannot have producer bit on. | ||
54 | EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0); | ||
55 | // Consumer state mask must be a single, i.e. power of 2. | ||
56 | EXPECT_NE(c2->buffer_state_bit(), 0); | ||
57 | EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0); | ||
58 | // Each consumer should have unique bit. | ||
59 | EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0); | ||
60 | |||
61 | // Initial state: producer not available, consumers not available. | ||
62 | EXPECT_EQ(0, RETRY_EINTR(p->Poll(100))); | ||
63 | EXPECT_EQ(0, RETRY_EINTR(c->Poll(100))); | ||
64 | EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100))); | ||
65 | |||
40 | EXPECT_EQ(0, p->Post(LocalHandle(), kContext)); | 66 | EXPECT_EQ(0, p->Post(LocalHandle(), kContext)); |
41 | // Both consumers should be triggered. | 67 | |
42 | EXPECT_GE(0, RETRY_EINTR(p->Poll(0))); | 68 | // New state: producer not available, consumers available. |
43 | EXPECT_LT(0, RETRY_EINTR(c->Poll(10))); | 69 | EXPECT_EQ(0, RETRY_EINTR(p->Poll(100))); |
44 | EXPECT_LT(0, RETRY_EINTR(c2->Poll(10))); | 70 | EXPECT_EQ(1, RETRY_EINTR(c->Poll(100))); |
71 | EXPECT_EQ(1, RETRY_EINTR(c2->Poll(100))); | ||
45 | 72 | ||
46 | uint64_t context; | 73 | uint64_t context; |
47 | LocalHandle fence; | 74 | LocalHandle fence; |
48 | EXPECT_LE(0, c->Acquire(&fence, &context)); | 75 | EXPECT_EQ(0, c->Acquire(&fence, &context)); |
49 | EXPECT_EQ(kContext, context); | 76 | EXPECT_EQ(kContext, context); |
50 | EXPECT_GE(0, RETRY_EINTR(c->Poll(0))); | 77 | EXPECT_EQ(0, RETRY_EINTR(c->Poll(100))); |
78 | EXPECT_EQ(1, RETRY_EINTR(c2->Poll(100))); | ||
51 | 79 | ||
52 | EXPECT_LE(0, c2->Acquire(&fence, &context)); | 80 | EXPECT_EQ(0, c2->Acquire(&fence, &context)); |
53 | EXPECT_EQ(kContext, context); | 81 | EXPECT_EQ(kContext, context); |
54 | EXPECT_GE(0, RETRY_EINTR(c2->Poll(0))); | 82 | EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100))); |
83 | EXPECT_EQ(0, RETRY_EINTR(c->Poll(100))); | ||
55 | 84 | ||
56 | EXPECT_EQ(0, c->Release(LocalHandle())); | 85 | EXPECT_EQ(0, c->Release(LocalHandle())); |
57 | EXPECT_GE(0, RETRY_EINTR(p->Poll(0))); | 86 | EXPECT_EQ(0, RETRY_EINTR(p->Poll(100))); |
58 | EXPECT_EQ(0, c2->Discard()); | 87 | EXPECT_EQ(0, c2->Discard()); |
59 | 88 | ||
60 | EXPECT_LE(0, RETRY_EINTR(p->Poll(0))); | 89 | EXPECT_EQ(1, RETRY_EINTR(p->Poll(100))); |
61 | EXPECT_EQ(0, p->Gain(&fence)); | 90 | EXPECT_EQ(0, p->Gain(&fence)); |
62 | EXPECT_GE(0, RETRY_EINTR(p->Poll(0))); | 91 | EXPECT_EQ(0, RETRY_EINTR(p->Poll(100))); |
92 | EXPECT_EQ(0, RETRY_EINTR(c->Poll(100))); | ||
93 | EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100))); | ||
94 | } | ||
95 | |||
96 | TEST_F(LibBufferHubTest, TestEpoll) { | ||
97 | std::unique_ptr<BufferProducer> p = BufferProducer::Create( | ||
98 | kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | ||
99 | ASSERT_TRUE(p.get() != nullptr); | ||
100 | std::unique_ptr<BufferConsumer> c = | ||
101 | BufferConsumer::Import(p->CreateConsumer()); | ||
102 | ASSERT_TRUE(c.get() != nullptr); | ||
103 | |||
104 | LocalHandle epoll_fd{epoll_create1(EPOLL_CLOEXEC)}; | ||
105 | ASSERT_TRUE(epoll_fd.IsValid()); | ||
106 | |||
107 | epoll_event event; | ||
108 | std::array<epoll_event, 64> events; | ||
109 | |||
110 | auto event_sources = p->GetEventSources(); | ||
111 | ASSERT_LT(event_sources.size(), events.size()); | ||
112 | |||
113 | for (const auto& event_source : event_sources) { | ||
114 | event = {.events = event_source.event_mask | EPOLLET, | ||
115 | .data = {.fd = p->event_fd()}}; | ||
116 | ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd, | ||
117 | &event)); | ||
118 | } | ||
119 | |||
120 | event_sources = c->GetEventSources(); | ||
121 | ASSERT_LT(event_sources.size(), events.size()); | ||
122 | |||
123 | for (const auto& event_source : event_sources) { | ||
124 | event = {.events = event_source.event_mask | EPOLLET, | ||
125 | .data = {.fd = c->event_fd()}}; | ||
126 | ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd, | ||
127 | &event)); | ||
128 | } | ||
129 | |||
130 | // No events should be signaled initially. | ||
131 | ASSERT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 0)); | ||
132 | |||
133 | // Post the producer and check for consumer signal. | ||
134 | EXPECT_EQ(0, p->Post({}, kContext)); | ||
135 | ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); | ||
136 | ASSERT_TRUE(events[0].events & EPOLLIN); | ||
137 | ASSERT_EQ(c->event_fd(), events[0].data.fd); | ||
138 | |||
139 | // Save the event bits to translate later. | ||
140 | event = events[0]; | ||
141 | |||
142 | // Check for events again. Edge-triggered mode should prevent any. | ||
143 | EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); | ||
144 | EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); | ||
145 | EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); | ||
146 | EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); | ||
147 | |||
148 | // Translate the events. | ||
149 | auto event_status = c->GetEventMask(event.events); | ||
150 | ASSERT_TRUE(event_status); | ||
151 | ASSERT_TRUE(event_status.get() & EPOLLIN); | ||
152 | |||
153 | // Check for events again. Edge-triggered mode should prevent any. | ||
154 | EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100)); | ||
155 | } | ||
156 | |||
157 | TEST_F(LibBufferHubTest, TestStateMask) { | ||
158 | std::unique_ptr<BufferProducer> p = BufferProducer::Create( | ||
159 | kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | ||
160 | ASSERT_TRUE(p.get() != nullptr); | ||
161 | |||
162 | // It's ok to create up to 63 consumer buffers. | ||
163 | uint64_t buffer_state_bits = p->buffer_state_bit(); | ||
164 | std::array<std::unique_ptr<BufferConsumer>, 63> cs; | ||
165 | for (size_t i = 0; i < 63; i++) { | ||
166 | cs[i] = BufferConsumer::Import(p->CreateConsumer()); | ||
167 | ASSERT_TRUE(cs[i].get() != nullptr); | ||
168 | // Expect all buffers have unique state mask. | ||
169 | EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0); | ||
170 | buffer_state_bits |= cs[i]->buffer_state_bit(); | ||
171 | } | ||
172 | EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask); | ||
173 | |||
174 | // The 64th creation will fail with out-of-memory error. | ||
175 | auto state = p->CreateConsumer(); | ||
176 | EXPECT_EQ(state.error(), E2BIG); | ||
177 | |||
178 | // Release any consumer should allow us to re-create. | ||
179 | for (size_t i = 0; i < 63; i++) { | ||
180 | buffer_state_bits &= ~cs[i]->buffer_state_bit(); | ||
181 | cs[i] = nullptr; | ||
182 | cs[i] = BufferConsumer::Import(p->CreateConsumer()); | ||
183 | ASSERT_TRUE(cs[i].get() != nullptr); | ||
184 | // The released state mask will be reused. | ||
185 | EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0); | ||
186 | buffer_state_bits |= cs[i]->buffer_state_bit(); | ||
187 | EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask); | ||
188 | } | ||
63 | } | 189 | } |
64 | 190 | ||
65 | TEST_F(LibBufferHubTest, TestStateTransitions) { | 191 | TEST_F(LibBufferHubTest, TestStateTransitions) { |
@@ -98,6 +224,7 @@ TEST_F(LibBufferHubTest, TestStateTransitions) { | |||
98 | 224 | ||
99 | // Release in acquired state should succeed. | 225 | // Release in acquired state should succeed. |
100 | EXPECT_EQ(0, c->Release(LocalHandle())); | 226 | EXPECT_EQ(0, c->Release(LocalHandle())); |
227 | EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); | ||
101 | 228 | ||
102 | // Release, acquire, and post in released state should fail. | 229 | // Release, acquire, and post in released state should fail. |
103 | EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); | 230 | EXPECT_EQ(-EBUSY, c->Release(LocalHandle())); |
@@ -144,6 +271,11 @@ TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) { | |||
144 | int64_t field1; | 271 | int64_t field1; |
145 | int64_t field2; | 272 | int64_t field2; |
146 | }; | 273 | }; |
274 | struct OverSizedMetadata { | ||
275 | int64_t field1; | ||
276 | int64_t field2; | ||
277 | int64_t field3; | ||
278 | }; | ||
147 | std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 279 | std::unique_ptr<BufferProducer> p = BufferProducer::Create( |
148 | kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); | 280 | kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); |
149 | ASSERT_TRUE(p.get() != nullptr); | 281 | ASSERT_TRUE(p.get() != nullptr); |
@@ -151,9 +283,16 @@ TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) { | |||
151 | BufferConsumer::Import(p->CreateConsumer()); | 283 | BufferConsumer::Import(p->CreateConsumer()); |
152 | ASSERT_TRUE(c.get() != nullptr); | 284 | ASSERT_TRUE(c.get() != nullptr); |
153 | 285 | ||
154 | int64_t sequence = 3; | 286 | // It is illegal to post metadata larger than originally requested during |
155 | EXPECT_NE(0, p->Post(LocalHandle(), sequence)); | 287 | // buffer allocation. |
288 | OverSizedMetadata evil_meta = {}; | ||
289 | EXPECT_NE(0, p->Post(LocalHandle(), evil_meta)); | ||
156 | EXPECT_GE(0, RETRY_EINTR(c->Poll(10))); | 290 | EXPECT_GE(0, RETRY_EINTR(c->Poll(10))); |
291 | |||
292 | // It is ok to post metadata smaller than originally requested during | ||
293 | // buffer allocation. | ||
294 | int64_t sequence = 42; | ||
295 | EXPECT_EQ(0, p->Post(LocalHandle(), sequence)); | ||
157 | } | 296 | } |
158 | 297 | ||
159 | TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) { | 298 | TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) { |
@@ -161,6 +300,11 @@ TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) { | |||
161 | int64_t field1; | 300 | int64_t field1; |
162 | int64_t field2; | 301 | int64_t field2; |
163 | }; | 302 | }; |
303 | struct OverSizedMetadata { | ||
304 | int64_t field1; | ||
305 | int64_t field2; | ||
306 | int64_t field3; | ||
307 | }; | ||
164 | std::unique_ptr<BufferProducer> p = BufferProducer::Create( | 308 | std::unique_ptr<BufferProducer> p = BufferProducer::Create( |
165 | kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); | 309 | kWidth, kHeight, kFormat, kUsage, sizeof(Metadata)); |
166 | ASSERT_TRUE(p.get() != nullptr); | 310 | ASSERT_TRUE(p.get() != nullptr); |
@@ -173,7 +317,16 @@ TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) { | |||
173 | 317 | ||
174 | LocalHandle fence; | 318 | LocalHandle fence; |
175 | int64_t sequence; | 319 | int64_t sequence; |
176 | EXPECT_NE(0, c->Acquire(&fence, &sequence)); | 320 | OverSizedMetadata e; |
321 | |||
322 | // It is illegal to acquire metadata larger than originally requested during | ||
323 | // buffer allocation. | ||
324 | EXPECT_NE(0, c->Acquire(&fence, &e)); | ||
325 | |||
326 | // It is ok to acquire metadata smaller than originally requested during | ||
327 | // buffer allocation. | ||
328 | EXPECT_EQ(0, c->Acquire(&fence, &sequence)); | ||
329 | EXPECT_EQ(m.field1, sequence); | ||
177 | } | 330 | } |
178 | 331 | ||
179 | TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) { | 332 | TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) { |
@@ -266,12 +419,140 @@ TEST_F(LibBufferHubTest, TestRemovePersistentBuffer) { | |||
266 | LocalHandle fence; | 419 | LocalHandle fence; |
267 | auto c = BufferConsumer::Import(p->CreateConsumer()); | 420 | auto c = BufferConsumer::Import(p->CreateConsumer()); |
268 | ASSERT_NE(nullptr, c); | 421 | ASSERT_NE(nullptr, c); |
269 | EXPECT_NE(-EPIPE, c->Acquire(&fence)); | 422 | EXPECT_EQ(0, p->Post<void>(LocalHandle())); |
423 | EXPECT_EQ(0, c->Acquire(&fence)); | ||
424 | EXPECT_EQ(0, c->Release(LocalHandle())); | ||
425 | EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); | ||
270 | 426 | ||
271 | // Test that removing persistence and closing the producer orphans the | 427 | // Test that removing persistence and closing the producer orphans the |
272 | // consumer. | 428 | // consumer. |
429 | EXPECT_EQ(0, p->Gain(&fence)); | ||
430 | EXPECT_EQ(0, p->Post<void>(LocalHandle())); | ||
273 | EXPECT_EQ(0, p->RemovePersistence()); | 431 | EXPECT_EQ(0, p->RemovePersistence()); |
274 | p = nullptr; | 432 | p = nullptr; |
275 | 433 | ||
434 | // Orphaned consumer can acquire the posted buffer one more time in | ||
435 | // asynchronous manner. But synchronous call will fail. | ||
436 | DvrNativeBufferMetadata meta; | ||
437 | EXPECT_EQ(0, c->AcquireAsync(&meta, &fence)); | ||
276 | EXPECT_EQ(-EPIPE, c->Release(LocalHandle())); | 438 | EXPECT_EQ(-EPIPE, c->Release(LocalHandle())); |
277 | } | 439 | } |
440 | |||
441 | namespace { | ||
442 | |||
443 | int PollFd(int fd, int timeout_ms) { | ||
444 | pollfd p = {fd, POLLIN, 0}; | ||
445 | return poll(&p, 1, timeout_ms); | ||
446 | } | ||
447 | |||
448 | } // namespace | ||
449 | |||
450 | TEST_F(LibBufferHubTest, TestAcquireFence) { | ||
451 | std::unique_ptr<BufferProducer> p = BufferProducer::Create( | ||
452 | kWidth, kHeight, kFormat, kUsage, /*metadata_size=*/0); | ||
453 | ASSERT_TRUE(p.get() != nullptr); | ||
454 | std::unique_ptr<BufferConsumer> c = | ||
455 | BufferConsumer::Import(p->CreateConsumer()); | ||
456 | ASSERT_TRUE(c.get() != nullptr); | ||
457 | |||
458 | DvrNativeBufferMetadata meta; | ||
459 | LocalHandle f1(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); | ||
460 | |||
461 | // Post with unsignaled fence. | ||
462 | EXPECT_EQ(0, p->PostAsync(&meta, f1)); | ||
463 | |||
464 | // Should acquire a valid fence. | ||
465 | LocalHandle f2; | ||
466 | EXPECT_LT(0, RETRY_EINTR(c->Poll(10))); | ||
467 | EXPECT_EQ(0, c->AcquireAsync(&meta, &f2)); | ||
468 | EXPECT_TRUE(f2.IsValid()); | ||
469 | // The original fence and acquired fence should have different fd number. | ||
470 | EXPECT_NE(f1.Get(), f2.Get()); | ||
471 | EXPECT_GE(0, PollFd(f2.Get(), 0)); | ||
472 | |||
473 | // Signal the original fence will trigger the new fence. | ||
474 | eventfd_write(f1.Get(), 1); | ||
475 | // Now the original FD has been signaled. | ||
476 | EXPECT_LT(0, PollFd(f2.Get(), 10)); | ||
477 | |||
478 | // Release the consumer with an invalid fence. | ||
479 | EXPECT_EQ(0, c->ReleaseAsync(&meta, LocalHandle())); | ||
480 | |||
481 | // Should gain an invalid fence. | ||
482 | LocalHandle f3; | ||
483 | EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); | ||
484 | EXPECT_EQ(0, p->GainAsync(&meta, &f3)); | ||
485 | EXPECT_FALSE(f3.IsValid()); | ||
486 | |||
487 | // Post with a signaled fence. | ||
488 | EXPECT_EQ(0, p->PostAsync(&meta, f1)); | ||
489 | |||
490 | // Should acquire a valid fence and it's already signalled. | ||
491 | LocalHandle f4; | ||
492 | EXPECT_LT(0, RETRY_EINTR(c->Poll(10))); | ||
493 | EXPECT_EQ(0, c->AcquireAsync(&meta, &f4)); | ||
494 | EXPECT_TRUE(f4.IsValid()); | ||
495 | EXPECT_LT(0, PollFd(f4.Get(), 10)); | ||
496 | |||
497 | // Release with an unsignalled fence and signal it immediately after release | ||
498 | // without producer gainning. | ||
499 | LocalHandle f5(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); | ||
500 | EXPECT_EQ(0, c->ReleaseAsync(&meta, f5)); | ||
501 | eventfd_write(f5.Get(), 1); | ||
502 | |||
503 | // Should gain a valid fence, which is already signaled. | ||
504 | LocalHandle f6; | ||
505 | EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); | ||
506 | EXPECT_EQ(0, p->GainAsync(&meta, &f6)); | ||
507 | EXPECT_TRUE(f6.IsValid()); | ||
508 | EXPECT_LT(0, PollFd(f6.Get(), 10)); | ||
509 | } | ||
510 | |||
511 | TEST_F(LibBufferHubTest, TestOrphanedAcquire) { | ||
512 | std::unique_ptr<BufferProducer> p = BufferProducer::Create( | ||
513 | kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); | ||
514 | ASSERT_TRUE(p.get() != nullptr); | ||
515 | std::unique_ptr<BufferConsumer> c1 = | ||
516 | BufferConsumer::Import(p->CreateConsumer()); | ||
517 | ASSERT_TRUE(c1.get() != nullptr); | ||
518 | const uint64_t consumer_state_bit1 = c1->buffer_state_bit(); | ||
519 | |||
520 | DvrNativeBufferMetadata meta; | ||
521 | EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle())); | ||
522 | |||
523 | LocalHandle fence; | ||
524 | EXPECT_LT(0, RETRY_EINTR(c1->Poll(10))); | ||
525 | EXPECT_LE(0, c1->AcquireAsync(&meta, &fence)); | ||
526 | // Destroy the consumer now will make it orphaned and the buffer is still | ||
527 | // acquired. | ||
528 | c1 = nullptr; | ||
529 | EXPECT_GE(0, RETRY_EINTR(p->Poll(10))); | ||
530 | |||
531 | std::unique_ptr<BufferConsumer> c2 = | ||
532 | BufferConsumer::Import(p->CreateConsumer()); | ||
533 | ASSERT_TRUE(c2.get() != nullptr); | ||
534 | const uint64_t consumer_state_bit2 = c2->buffer_state_bit(); | ||
535 | EXPECT_NE(consumer_state_bit1, consumer_state_bit2); | ||
536 | |||
537 | // The new consumer is available for acquire. | ||
538 | EXPECT_LT(0, RETRY_EINTR(c2->Poll(10))); | ||
539 | EXPECT_LE(0, c2->AcquireAsync(&meta, &fence)); | ||
540 | // Releasing the consumer makes the buffer gainable. | ||
541 | EXPECT_EQ(0, c2->ReleaseAsync(&meta, LocalHandle())); | ||
542 | |||
543 | // The buffer is now available for the producer to gain. | ||
544 | EXPECT_LT(0, RETRY_EINTR(p->Poll(10))); | ||
545 | |||
546 | // But if another consumer is created in released state. | ||
547 | std::unique_ptr<BufferConsumer> c3 = | ||
548 | BufferConsumer::Import(p->CreateConsumer()); | ||
549 | ASSERT_TRUE(c3.get() != nullptr); | ||
550 | const uint64_t consumer_state_bit3 = c3->buffer_state_bit(); | ||
551 | EXPECT_NE(consumer_state_bit2, consumer_state_bit3); | ||
552 | // The consumer buffer is not acquirable. | ||
553 | EXPECT_GE(0, RETRY_EINTR(c3->Poll(10))); | ||
554 | EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence)); | ||
555 | |||
556 | // Producer should be able to gain no matter what. | ||
557 | EXPECT_EQ(0, p->GainAsync(&meta, &fence)); | ||
558 | } | ||
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h index be20e72a8..1186f9348 100644 --- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h +++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h | |||
@@ -11,6 +11,8 @@ | |||
11 | 11 | ||
12 | #include <private/dvr/ion_buffer.h> | 12 | #include <private/dvr/ion_buffer.h> |
13 | 13 | ||
14 | #include "bufferhub_rpc.h" | ||
15 | |||
14 | namespace android { | 16 | namespace android { |
15 | namespace dvr { | 17 | namespace dvr { |
16 | 18 | ||
@@ -75,6 +77,14 @@ class BufferHubBuffer : public pdx::Client { | |||
75 | } | 77 | } |
76 | } | 78 | } |
77 | 79 | ||
80 | std::vector<pdx::ClientChannel::EventSource> GetEventSources() const { | ||
81 | if (auto* client_channel = GetChannel()) { | ||
82 | return client_channel->GetEventSources(); | ||
83 | } else { | ||
84 | return {}; | ||
85 | } | ||
86 | } | ||
87 | |||
78 | native_handle_t* native_handle() const { | 88 | native_handle_t* native_handle() const { |
79 | return const_cast<native_handle_t*>(buffer_.handle()); | 89 | return const_cast<native_handle_t*>(buffer_.handle()); |
80 | } | 90 | } |
@@ -84,6 +94,10 @@ class BufferHubBuffer : public pdx::Client { | |||
84 | 94 | ||
85 | int id() const { return id_; } | 95 | int id() const { return id_; } |
86 | 96 | ||
97 | // A state mask which is unique to a buffer hub client among all its siblings | ||
98 | // sharing the same concrete graphic buffer. | ||
99 | uint64_t buffer_state_bit() const { return buffer_state_bit_; } | ||
100 | |||
87 | // The following methods return settings of the first buffer. Currently, | 101 | // The following methods return settings of the first buffer. Currently, |
88 | // it is only possible to create multi-buffer BufferHubBuffers with the same | 102 | // it is only possible to create multi-buffer BufferHubBuffers with the same |
89 | // settings. | 103 | // settings. |
@@ -98,6 +112,9 @@ class BufferHubBuffer : public pdx::Client { | |||
98 | uint64_t producer_usage() const { return buffer_.usage(); } | 112 | uint64_t producer_usage() const { return buffer_.usage(); } |
99 | uint64_t consumer_usage() const { return buffer_.usage(); } | 113 | uint64_t consumer_usage() const { return buffer_.usage(); } |
100 | 114 | ||
115 | uint64_t GetQueueIndex() const { return metadata_header_->queue_index; } | ||
116 | void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; } | ||
117 | |||
101 | protected: | 118 | protected: |
102 | explicit BufferHubBuffer(LocalChannelHandle channel); | 119 | explicit BufferHubBuffer(LocalChannelHandle channel); |
103 | explicit BufferHubBuffer(const std::string& endpoint_path); | 120 | explicit BufferHubBuffer(const std::string& endpoint_path); |
@@ -106,6 +123,31 @@ class BufferHubBuffer : public pdx::Client { | |||
106 | // Initialization helper. | 123 | // Initialization helper. |
107 | int ImportBuffer(); | 124 | int ImportBuffer(); |
108 | 125 | ||
126 | // Check invalid metadata operation. Returns 0 if requested metadata is valid. | ||
127 | int CheckMetadata(size_t user_metadata_size) const; | ||
128 | |||
129 | // Send out the new fence by updating the shared fence (shared_release_fence | ||
130 | // for producer and shared_acquire_fence for consumer). Note that during this | ||
131 | // should only be used in LocalPost() or LocalRelease, and the shared fence | ||
132 | // shouldn't be poll'ed by the other end. | ||
133 | int UpdateSharedFence(const LocalHandle& new_fence, | ||
134 | const LocalHandle& shared_fence); | ||
135 | |||
136 | // IonBuffer that is shared between bufferhubd, producer, and consumers. | ||
137 | size_t metadata_buf_size_{0}; | ||
138 | size_t user_metadata_size_{0}; | ||
139 | BufferHubDefs::MetadataHeader* metadata_header_{nullptr}; | ||
140 | void* user_metadata_ptr_{nullptr}; | ||
141 | std::atomic<uint64_t>* buffer_state_{nullptr}; | ||
142 | std::atomic<uint64_t>* fence_state_{nullptr}; | ||
143 | |||
144 | LocalHandle shared_acquire_fence_; | ||
145 | LocalHandle shared_release_fence_; | ||
146 | |||
147 | // A local fence fd that holds the ownership of the fence fd on Post (for | ||
148 | // producer) and Release (for consumer). | ||
149 | LocalHandle pending_fence_fd_; | ||
150 | |||
109 | private: | 151 | private: |
110 | BufferHubBuffer(const BufferHubBuffer&) = delete; | 152 | BufferHubBuffer(const BufferHubBuffer&) = delete; |
111 | void operator=(const BufferHubBuffer&) = delete; | 153 | void operator=(const BufferHubBuffer&) = delete; |
@@ -114,8 +156,9 @@ class BufferHubBuffer : public pdx::Client { | |||
114 | // for logging and debugging purposes only and should not be used for lookup | 156 | // for logging and debugging purposes only and should not be used for lookup |
115 | // or any other functional purpose as a security precaution. | 157 | // or any other functional purpose as a security precaution. |
116 | int id_; | 158 | int id_; |
117 | 159 | uint64_t buffer_state_bit_{0ULL}; | |
118 | IonBuffer buffer_; | 160 | IonBuffer buffer_; |
161 | IonBuffer metadata_buffer_; | ||
119 | }; | 162 | }; |
120 | 163 | ||
121 | // This represents a writable buffer. Calling Post notifies all clients and | 164 | // This represents a writable buffer. Calling Post notifies all clients and |
@@ -136,12 +179,17 @@ class BufferProducer : public pdx::ClientBase<BufferProducer, BufferHubBuffer> { | |||
136 | static std::unique_ptr<BufferProducer> Import( | 179 | static std::unique_ptr<BufferProducer> Import( |
137 | Status<LocalChannelHandle> status); | 180 | Status<LocalChannelHandle> status); |
138 | 181 | ||
182 | // Asynchronously posts a buffer. The fence and metadata are passed to | ||
183 | // consumer via shared fd and shared memory. | ||
184 | int PostAsync(const DvrNativeBufferMetadata* meta, | ||
185 | const LocalHandle& ready_fence); | ||
186 | |||
139 | // Post this buffer, passing |ready_fence| to the consumers. The bytes in | 187 | // Post this buffer, passing |ready_fence| to the consumers. The bytes in |
140 | // |meta| are passed unaltered to the consumers. The producer must not modify | 188 | // |meta| are passed unaltered to the consumers. The producer must not modify |
141 | // the buffer until it is re-gained. | 189 | // the buffer until it is re-gained. |
142 | // This returns zero or a negative unix error code. | 190 | // This returns zero or a negative unix error code. |
143 | int Post(const LocalHandle& ready_fence, const void* meta, | 191 | int Post(const LocalHandle& ready_fence, const void* meta, |
144 | size_t meta_size_bytes); | 192 | size_t user_metadata_size); |
145 | 193 | ||
146 | template <typename Meta, | 194 | template <typename Meta, |
147 | typename = typename std::enable_if<std::is_void<Meta>::value>::type> | 195 | typename = typename std::enable_if<std::is_void<Meta>::value>::type> |
@@ -160,16 +208,15 @@ class BufferProducer : public pdx::ClientBase<BufferProducer, BufferHubBuffer> { | |||
160 | // is in the released state. | 208 | // is in the released state. |
161 | // This returns zero or a negative unix error code. | 209 | // This returns zero or a negative unix error code. |
162 | int Gain(LocalHandle* release_fence); | 210 | int Gain(LocalHandle* release_fence); |
211 | int GainAsync(); | ||
163 | 212 | ||
164 | // Asynchronously marks a released buffer as gained. This method is similar to | 213 | // Asynchronously marks a released buffer as gained. This method is similar to |
165 | // the synchronous version above, except that it does not wait for BufferHub | 214 | // the synchronous version above, except that it does not wait for BufferHub |
166 | // to acknowledge success or failure, nor does it transfer a release fence to | 215 | // to acknowledge success or failure. Because of the asynchronous nature of |
167 | // the client. This version may be used in situations where a release fence is | 216 | // the underlying message, no error is returned if this method is called when |
168 | // not needed. Because of the asynchronous nature of the underlying message, | 217 | // the buffer is in an incorrect state. Returns zero if sending the message |
169 | // no error is returned if this method is called when the buffer is in an | 218 | // succeeded, or a negative errno code if local error check fails. |
170 | // incorrect state. Returns zero if sending the message succeeded, or a | 219 | int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence); |
171 | // negative errno code otherwise. | ||
172 | int GainAsync(); | ||
173 | 220 | ||
174 | // Attaches the producer to |name| so that it becomes a persistent buffer that | 221 | // Attaches the producer to |name| so that it becomes a persistent buffer that |
175 | // may be retrieved by name at a later time. This may be used in cases where a | 222 | // may be retrieved by name at a later time. This may be used in cases where a |
@@ -216,7 +263,7 @@ class BufferProducer : public pdx::ClientBase<BufferProducer, BufferHubBuffer> { | |||
216 | BufferProducer(const std::string& name, int user_id, int group_id, | 263 | BufferProducer(const std::string& name, int user_id, int group_id, |
217 | uint32_t width, uint32_t height, uint32_t format, | 264 | uint32_t width, uint32_t height, uint32_t format, |
218 | uint64_t producer_usage, uint64_t consumer_usage, | 265 | uint64_t producer_usage, uint64_t consumer_usage, |
219 | size_t meta_size_bytes); | 266 | size_t user_metadata_size); |
220 | 267 | ||
221 | // Constructs a blob (flat) buffer with the given usage flags. | 268 | // Constructs a blob (flat) buffer with the given usage flags. |
222 | BufferProducer(uint32_t usage, size_t size); | 269 | BufferProducer(uint32_t usage, size_t size); |
@@ -234,6 +281,11 @@ class BufferProducer : public pdx::ClientBase<BufferProducer, BufferHubBuffer> { | |||
234 | 281 | ||
235 | // Imports the given file handle to a producer channel, taking ownership. | 282 | // Imports the given file handle to a producer channel, taking ownership. |
236 | explicit BufferProducer(LocalChannelHandle channel); | 283 | explicit BufferProducer(LocalChannelHandle channel); |
284 | |||
285 | // Local state transition helpers. | ||
286 | int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence); | ||
287 | int LocalPost(const DvrNativeBufferMetadata* meta, | ||
288 | const LocalHandle& ready_fence); | ||
237 | }; | 289 | }; |
238 | 290 | ||
239 | // This is a connection to a producer buffer, which can be located in another | 291 | // This is a connection to a producer buffer, which can be located in another |
@@ -263,7 +315,7 @@ class BufferConsumer : public pdx::ClientBase<BufferConsumer, BufferHubBuffer> { | |||
263 | // are available. This call will only succeed if the buffer is in the posted | 315 | // are available. This call will only succeed if the buffer is in the posted |
264 | // state. | 316 | // state. |
265 | // Returns zero on success, or a negative errno code otherwise. | 317 | // Returns zero on success, or a negative errno code otherwise. |
266 | int Acquire(LocalHandle* ready_fence, void* meta, size_t meta_size_bytes); | 318 | int Acquire(LocalHandle* ready_fence, void* meta, size_t user_metadata_size); |
267 | 319 | ||
268 | // Attempt to retrieve a post event from buffer hub. If successful, | 320 | // Attempt to retrieve a post event from buffer hub. If successful, |
269 | // |ready_fence| is set to a fence to wait on until the buffer is ready. This | 321 | // |ready_fence| is set to a fence to wait on until the buffer is ready. This |
@@ -274,20 +326,22 @@ class BufferConsumer : public pdx::ClientBase<BufferConsumer, BufferHubBuffer> { | |||
274 | return Acquire(ready_fence, meta, sizeof(*meta)); | 326 | return Acquire(ready_fence, meta, sizeof(*meta)); |
275 | } | 327 | } |
276 | 328 | ||
329 | // Asynchronously acquires a bufer. | ||
330 | int AcquireAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence); | ||
331 | |||
277 | // This should be called after a successful Acquire call. If the fence is | 332 | // This should be called after a successful Acquire call. If the fence is |
278 | // valid the fence determines the buffer usage, otherwise the buffer is | 333 | // valid the fence determines the buffer usage, otherwise the buffer is |
279 | // released immediately. | 334 | // released immediately. |
280 | // This returns zero or a negative unix error code. | 335 | // This returns zero or a negative unix error code. |
281 | int Release(const LocalHandle& release_fence); | 336 | int Release(const LocalHandle& release_fence); |
337 | int ReleaseAsync(); | ||
282 | 338 | ||
283 | // Asynchronously releases a buffer. Similar to the synchronous version above, | 339 | // Asynchronously releases a buffer. Similar to the synchronous version above, |
284 | // except that it does not wait for BufferHub to reply with success or error, | 340 | // except that it does not wait for BufferHub to reply with success or error. |
285 | // nor does it transfer a release fence. This version may be used in | 341 | // The fence and metadata are passed to consumer via shared fd and shared |
286 | // situations where a release fence is not needed. Because of the asynchronous | 342 | // memory. |
287 | // nature of the underlying message, no error is returned if this method is | 343 | int ReleaseAsync(const DvrNativeBufferMetadata* meta, |
288 | // called when the buffer is in an incorrect state. Returns zero if sending | 344 | const LocalHandle& release_fence); |
289 | // the message succeeded, or a negative errno code otherwise. | ||
290 | int ReleaseAsync(); | ||
291 | 345 | ||
292 | // May be called after or instead of Acquire to indicate that the consumer | 346 | // May be called after or instead of Acquire to indicate that the consumer |
293 | // does not need to access the buffer this cycle. This returns zero or a | 347 | // does not need to access the buffer this cycle. This returns zero or a |
@@ -305,6 +359,11 @@ class BufferConsumer : public pdx::ClientBase<BufferConsumer, BufferHubBuffer> { | |||
305 | friend BASE; | 359 | friend BASE; |
306 | 360 | ||
307 | explicit BufferConsumer(LocalChannelHandle channel); | 361 | explicit BufferConsumer(LocalChannelHandle channel); |
362 | |||
363 | // Local state transition helpers. | ||
364 | int LocalAcquire(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence); | ||
365 | int LocalRelease(const DvrNativeBufferMetadata* meta, | ||
366 | const LocalHandle& release_fence); | ||
308 | }; | 367 | }; |
309 | 368 | ||
310 | } // namespace dvr | 369 | } // namespace dvr |
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h index ca0e0e082..f9fd42d7b 100644 --- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h +++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <gui/BufferQueueDefs.h> | 5 | #include <gui/BufferQueueDefs.h> |
6 | #include <sys/types.h> | 6 | #include <sys/types.h> |
7 | 7 | ||
8 | #include <dvr/dvr_api.h> | ||
8 | #include <pdx/channel_handle.h> | 9 | #include <pdx/channel_handle.h> |
9 | #include <pdx/file_handle.h> | 10 | #include <pdx/file_handle.h> |
10 | #include <pdx/rpc/remote_method.h> | 11 | #include <pdx/rpc/remote_method.h> |
@@ -14,6 +15,71 @@ | |||
14 | namespace android { | 15 | namespace android { |
15 | namespace dvr { | 16 | namespace dvr { |
16 | 17 | ||
18 | namespace BufferHubDefs { | ||
19 | |||
20 | static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB; | ||
21 | static constexpr uint32_t kMetadataUsage = | ||
22 | GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; | ||
23 | |||
24 | // Single producuer multiple (up to 63) consumers ownership signal. | ||
25 | // 64-bit atomic unsigned int. | ||
26 | // | ||
27 | // MSB LSB | ||
28 | // | | | ||
29 | // v v | ||
30 | // [P|C62|...|C1|C0] | ||
31 | // Gain'ed state: [0|..|0|0] -> Exclusively Writable. | ||
32 | // Post'ed state: [1|..|0|0] | ||
33 | // Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits | ||
34 | // Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits | ||
35 | static constexpr uint64_t kProducerStateBit = 1ULL << 63; | ||
36 | static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1; | ||
37 | |||
38 | static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state, | ||
39 | uint64_t clear_mask, uint64_t set_mask) { | ||
40 | uint64_t old_state; | ||
41 | uint64_t new_state; | ||
42 | do { | ||
43 | old_state = buffer_state->load(); | ||
44 | new_state = (old_state & ~clear_mask) | set_mask; | ||
45 | } while (!buffer_state->compare_exchange_weak(old_state, new_state)); | ||
46 | } | ||
47 | |||
48 | static inline bool IsBufferGained(uint64_t state) { return state == 0; } | ||
49 | |||
50 | static inline bool IsBufferPosted(uint64_t state, | ||
51 | uint64_t consumer_bit = kConsumerStateMask) { | ||
52 | return (state & kProducerStateBit) && !(state & consumer_bit); | ||
53 | } | ||
54 | |||
55 | static inline bool IsBufferAcquired(uint64_t state) { | ||
56 | return (state & kProducerStateBit) && (state & kConsumerStateMask); | ||
57 | } | ||
58 | |||
59 | static inline bool IsBufferReleased(uint64_t state) { | ||
60 | return !(state & kProducerStateBit) && (state & kConsumerStateMask); | ||
61 | } | ||
62 | |||
63 | struct __attribute__((packed, aligned(8))) MetadataHeader { | ||
64 | // Internal data format, which can be updated as long as the size, padding and | ||
65 | // field alignment of the struct is consistent within the same ABI. As this | ||
66 | // part is subject for future updates, it's not stable cross Android version, | ||
67 | // so don't have it visible from outside of the Android platform (include Apps | ||
68 | // and vendor HAL). | ||
69 | std::atomic<uint64_t> buffer_state; | ||
70 | std::atomic<uint64_t> fence_state; | ||
71 | uint64_t queue_index; | ||
72 | |||
73 | // Public data format, which should be updated with caution. See more details | ||
74 | // in dvr_api.h | ||
75 | DvrNativeBufferMetadata metadata; | ||
76 | }; | ||
77 | |||
78 | static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size"); | ||
79 | static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader); | ||
80 | |||
81 | } // namespace BufferHubDefs | ||
82 | |||
17 | template <typename FileHandleType> | 83 | template <typename FileHandleType> |
18 | class NativeBufferHandle { | 84 | class NativeBufferHandle { |
19 | public: | 85 | public: |
@@ -93,6 +159,57 @@ class NativeBufferHandle { | |||
93 | void operator=(const NativeBufferHandle&) = delete; | 159 | void operator=(const NativeBufferHandle&) = delete; |
94 | }; | 160 | }; |
95 | 161 | ||
162 | template <typename FileHandleType> | ||
163 | class BufferDescription { | ||
164 | public: | ||
165 | BufferDescription() = default; | ||
166 | BufferDescription(const IonBuffer& buffer, const IonBuffer& metadata, int id, | ||
167 | uint64_t buffer_state_bit, | ||
168 | const FileHandleType& acquire_fence_fd, | ||
169 | const FileHandleType& release_fence_fd) | ||
170 | : id_(id), | ||
171 | buffer_state_bit_(buffer_state_bit), | ||
172 | buffer_(buffer, id), | ||
173 | metadata_(metadata, id), | ||
174 | acquire_fence_fd_(acquire_fence_fd.Borrow()), | ||
175 | release_fence_fd_(release_fence_fd.Borrow()) {} | ||
176 | |||
177 | BufferDescription(BufferDescription&& other) = default; | ||
178 | BufferDescription& operator=(BufferDescription&& other) = default; | ||
179 | |||
180 | // ID of the buffer client. All BufferHubBuffer clients derived from the same | ||
181 | // buffer in bufferhubd share the same buffer id. | ||
182 | int id() const { return id_; } | ||
183 | // State mask of the buffer client. Each BufferHubBuffer client backed by the | ||
184 | // same buffer channel has uniqued state bit among its siblings. For a | ||
185 | // producer buffer the bit must be kProducerStateBit; for a consumer the bit | ||
186 | // must be one of the kConsumerStateMask. | ||
187 | uint64_t buffer_state_bit() const { return buffer_state_bit_; } | ||
188 | FileHandleType take_acquire_fence() { return std::move(acquire_fence_fd_); } | ||
189 | FileHandleType take_release_fence() { return std::move(release_fence_fd_); } | ||
190 | |||
191 | int ImportBuffer(IonBuffer* buffer) { return buffer_.Import(buffer); } | ||
192 | int ImportMetadata(IonBuffer* metadata) { return metadata_.Import(metadata); } | ||
193 | |||
194 | private: | ||
195 | int id_{-1}; | ||
196 | uint64_t buffer_state_bit_{0}; | ||
197 | // Two IonBuffers: one for the graphic buffer and one for metadata. | ||
198 | NativeBufferHandle<FileHandleType> buffer_; | ||
199 | NativeBufferHandle<FileHandleType> metadata_; | ||
200 | |||
201 | // Pamameters for shared fences. | ||
202 | FileHandleType acquire_fence_fd_; | ||
203 | FileHandleType release_fence_fd_; | ||
204 | |||
205 | PDX_SERIALIZABLE_MEMBERS(BufferDescription<FileHandleType>, id_, | ||
206 | buffer_state_bit_, buffer_, metadata_, | ||
207 | acquire_fence_fd_, release_fence_fd_); | ||
208 | |||
209 | BufferDescription(const BufferDescription&) = delete; | ||
210 | void operator=(const BufferDescription&) = delete; | ||
211 | }; | ||
212 | |||
96 | using BorrowedNativeBufferHandle = NativeBufferHandle<pdx::BorrowedHandle>; | 213 | using BorrowedNativeBufferHandle = NativeBufferHandle<pdx::BorrowedHandle>; |
97 | using LocalNativeBufferHandle = NativeBufferHandle<pdx::LocalHandle>; | 214 | using LocalNativeBufferHandle = NativeBufferHandle<pdx::LocalHandle>; |
98 | 215 | ||
@@ -149,11 +266,11 @@ struct ProducerQueueConfig { | |||
149 | 266 | ||
150 | // Size of the meta data associated with all the buffers allocated from the | 267 | // Size of the meta data associated with all the buffers allocated from the |
151 | // queue. | 268 | // queue. |
152 | size_t meta_size_bytes; | 269 | size_t user_metadata_size; |
153 | 270 | ||
154 | private: | 271 | private: |
155 | PDX_SERIALIZABLE_MEMBERS(ProducerQueueConfig, is_async, default_width, | 272 | PDX_SERIALIZABLE_MEMBERS(ProducerQueueConfig, is_async, default_width, |
156 | default_height, default_format, meta_size_bytes); | 273 | default_height, default_format, user_metadata_size); |
157 | }; | 274 | }; |
158 | 275 | ||
159 | class ProducerQueueConfigBuilder { | 276 | class ProducerQueueConfigBuilder { |
@@ -161,7 +278,7 @@ class ProducerQueueConfigBuilder { | |||
161 | // Build a ProducerQueueConfig object. | 278 | // Build a ProducerQueueConfig object. |
162 | ProducerQueueConfig Build() { | 279 | ProducerQueueConfig Build() { |
163 | return {is_async_, default_width_, default_height_, default_format_, | 280 | return {is_async_, default_width_, default_height_, default_format_, |
164 | meta_size_bytes_}; | 281 | user_metadata_size_}; |
165 | } | 282 | } |
166 | 283 | ||
167 | ProducerQueueConfigBuilder& SetIsAsync(bool is_async) { | 284 | ProducerQueueConfigBuilder& SetIsAsync(bool is_async) { |
@@ -186,12 +303,12 @@ class ProducerQueueConfigBuilder { | |||
186 | 303 | ||
187 | template <typename Meta> | 304 | template <typename Meta> |
188 | ProducerQueueConfigBuilder& SetMetadata() { | 305 | ProducerQueueConfigBuilder& SetMetadata() { |
189 | meta_size_bytes_ = sizeof(Meta); | 306 | user_metadata_size_ = sizeof(Meta); |
190 | return *this; | 307 | return *this; |
191 | } | 308 | } |
192 | 309 | ||
193 | ProducerQueueConfigBuilder& SetMetadataSize(size_t meta_size_bytes) { | 310 | ProducerQueueConfigBuilder& SetMetadataSize(size_t user_metadata_size) { |
194 | meta_size_bytes_ = meta_size_bytes; | 311 | user_metadata_size_ = user_metadata_size; |
195 | return *this; | 312 | return *this; |
196 | } | 313 | } |
197 | 314 | ||
@@ -200,7 +317,7 @@ class ProducerQueueConfigBuilder { | |||
200 | uint32_t default_width_{1}; | 317 | uint32_t default_width_{1}; |
201 | uint32_t default_height_{1}; | 318 | uint32_t default_height_{1}; |
202 | uint32_t default_format_{1}; // PIXEL_FORMAT_RGBA_8888 | 319 | uint32_t default_format_{1}; // PIXEL_FORMAT_RGBA_8888 |
203 | size_t meta_size_bytes_{0}; | 320 | size_t user_metadata_size_{0}; |
204 | }; | 321 | }; |
205 | 322 | ||
206 | // Explicit specializations of ProducerQueueConfigBuilder::Build for void | 323 | // Explicit specializations of ProducerQueueConfigBuilder::Build for void |
@@ -208,7 +325,7 @@ class ProducerQueueConfigBuilder { | |||
208 | template <> | 325 | template <> |
209 | inline ProducerQueueConfigBuilder& | 326 | inline ProducerQueueConfigBuilder& |
210 | ProducerQueueConfigBuilder::SetMetadata<void>() { | 327 | ProducerQueueConfigBuilder::SetMetadata<void>() { |
211 | meta_size_bytes_ = 0; | 328 | user_metadata_size_ = 0; |
212 | return *this; | 329 | return *this; |
213 | } | 330 | } |
214 | 331 | ||
@@ -269,7 +386,6 @@ struct BufferHubRPC { | |||
269 | }; | 386 | }; |
270 | 387 | ||
271 | // Aliases. | 388 | // Aliases. |
272 | using MetaData = pdx::rpc::BufferWrapper<std::uint8_t*>; | ||
273 | using LocalChannelHandle = pdx::LocalChannelHandle; | 389 | using LocalChannelHandle = pdx::LocalChannelHandle; |
274 | using LocalHandle = pdx::LocalHandle; | 390 | using LocalHandle = pdx::LocalHandle; |
275 | using Void = pdx::rpc::Void; | 391 | using Void = pdx::rpc::Void; |
@@ -277,25 +393,24 @@ struct BufferHubRPC { | |||
277 | // Methods. | 393 | // Methods. |
278 | PDX_REMOTE_METHOD(CreateBuffer, kOpCreateBuffer, | 394 | PDX_REMOTE_METHOD(CreateBuffer, kOpCreateBuffer, |
279 | void(uint32_t width, uint32_t height, uint32_t format, | 395 | void(uint32_t width, uint32_t height, uint32_t format, |
280 | uint64_t usage, size_t meta_size_bytes)); | 396 | uint64_t usage, size_t user_metadata_size)); |
281 | PDX_REMOTE_METHOD(CreatePersistentBuffer, kOpCreatePersistentBuffer, | 397 | PDX_REMOTE_METHOD(CreatePersistentBuffer, kOpCreatePersistentBuffer, |
282 | void(const std::string& name, int user_id, int group_id, | 398 | void(const std::string& name, int user_id, int group_id, |
283 | uint32_t width, uint32_t height, uint32_t format, | 399 | uint32_t width, uint32_t height, uint32_t format, |
284 | uint64_t usage, size_t meta_size_bytes)); | 400 | uint64_t usage, size_t user_metadata_size)); |
285 | PDX_REMOTE_METHOD(GetPersistentBuffer, kOpGetPersistentBuffer, | 401 | PDX_REMOTE_METHOD(GetPersistentBuffer, kOpGetPersistentBuffer, |
286 | void(const std::string& name)); | 402 | void(const std::string& name)); |
287 | PDX_REMOTE_METHOD(GetBuffer, kOpGetBuffer, | 403 | PDX_REMOTE_METHOD(GetBuffer, kOpGetBuffer, |
288 | NativeBufferHandle<LocalHandle>(Void)); | 404 | BufferDescription<LocalHandle>(Void)); |
289 | PDX_REMOTE_METHOD(NewConsumer, kOpNewConsumer, LocalChannelHandle(Void)); | 405 | PDX_REMOTE_METHOD(NewConsumer, kOpNewConsumer, LocalChannelHandle(Void)); |
290 | PDX_REMOTE_METHOD(ProducerMakePersistent, kOpProducerMakePersistent, | 406 | PDX_REMOTE_METHOD(ProducerMakePersistent, kOpProducerMakePersistent, |
291 | void(const std::string& name, int user_id, int group_id)); | 407 | void(const std::string& name, int user_id, int group_id)); |
292 | PDX_REMOTE_METHOD(ProducerRemovePersistence, kOpProducerRemovePersistence, | 408 | PDX_REMOTE_METHOD(ProducerRemovePersistence, kOpProducerRemovePersistence, |
293 | void(Void)); | 409 | void(Void)); |
294 | PDX_REMOTE_METHOD(ProducerPost, kOpProducerPost, | 410 | PDX_REMOTE_METHOD(ProducerPost, kOpProducerPost, |
295 | void(LocalFence acquire_fence, MetaData)); | 411 | void(LocalFence acquire_fence)); |
296 | PDX_REMOTE_METHOD(ProducerGain, kOpProducerGain, LocalFence(Void)); | 412 | PDX_REMOTE_METHOD(ProducerGain, kOpProducerGain, LocalFence(Void)); |
297 | PDX_REMOTE_METHOD(ConsumerAcquire, kOpConsumerAcquire, | 413 | PDX_REMOTE_METHOD(ConsumerAcquire, kOpConsumerAcquire, LocalFence(Void)); |
298 | std::pair<LocalFence, MetaData>(std::size_t metadata_size)); | ||
299 | PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease, | 414 | PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease, |
300 | void(LocalFence release_fence)); | 415 | void(LocalFence release_fence)); |
301 | PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore)); | 416 | PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore)); |
@@ -305,7 +420,7 @@ struct BufferHubRPC { | |||
305 | QueueInfo(const ProducerQueueConfig& producer_config, | 420 | QueueInfo(const ProducerQueueConfig& producer_config, |
306 | const UsagePolicy& usage_policy)); | 421 | const UsagePolicy& usage_policy)); |
307 | PDX_REMOTE_METHOD(CreateConsumerQueue, kOpCreateConsumerQueue, | 422 | PDX_REMOTE_METHOD(CreateConsumerQueue, kOpCreateConsumerQueue, |
308 | LocalChannelHandle(Void)); | 423 | LocalChannelHandle(bool silent_queue)); |
309 | PDX_REMOTE_METHOD(GetQueueInfo, kOpGetQueueInfo, QueueInfo(Void)); | 424 | PDX_REMOTE_METHOD(GetQueueInfo, kOpGetQueueInfo, QueueInfo(Void)); |
310 | PDX_REMOTE_METHOD(ProducerQueueAllocateBuffers, | 425 | PDX_REMOTE_METHOD(ProducerQueueAllocateBuffers, |
311 | kOpProducerQueueAllocateBuffers, | 426 | kOpProducerQueueAllocateBuffers, |
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp index 0b3b2f0fb..93ccd0fda 100644 --- a/libs/vr/libbufferhubqueue/Android.bp +++ b/libs/vr/libbufferhubqueue/Android.bp | |||
@@ -48,6 +48,7 @@ cc_library { | |||
48 | cflags: [ | 48 | cflags: [ |
49 | "-DLOG_TAG=\"libbufferhubqueue\"", | 49 | "-DLOG_TAG=\"libbufferhubqueue\"", |
50 | "-DTRACE=0", | 50 | "-DTRACE=0", |
51 | "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", | ||
51 | ], | 52 | ], |
52 | srcs: sourceFiles, | 53 | srcs: sourceFiles, |
53 | export_include_dirs: includeFiles, | 54 | export_include_dirs: includeFiles, |
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp index f9f87ff1b..8bea0cde7 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <pdx/default_transport/client_channel.h> | 10 | #include <pdx/default_transport/client_channel.h> |
11 | #include <pdx/default_transport/client_channel_factory.h> | 11 | #include <pdx/default_transport/client_channel_factory.h> |
12 | #include <pdx/file_handle.h> | 12 | #include <pdx/file_handle.h> |
13 | #include <pdx/trace.h> | ||
13 | 14 | ||
14 | #define RETRY_EINTR(fnc_call) \ | 15 | #define RETRY_EINTR(fnc_call) \ |
15 | ([&]() -> decltype(fnc_call) { \ | 16 | ([&]() -> decltype(fnc_call) { \ |
@@ -44,17 +45,6 @@ Status<int> PollEvents(int fd, short events) { | |||
44 | } | 45 | } |
45 | } | 46 | } |
46 | 47 | ||
47 | // Polls a buffer for the given events, taking care to do the proper | ||
48 | // translation. | ||
49 | Status<int> PollEvents(const std::shared_ptr<BufferHubBuffer>& buffer, | ||
50 | short events) { | ||
51 | auto poll_status = PollEvents(buffer->event_fd(), events); | ||
52 | if (!poll_status) | ||
53 | return poll_status; | ||
54 | |||
55 | return buffer->GetEventMask(poll_status.get()); | ||
56 | } | ||
57 | |||
58 | std::pair<int32_t, int32_t> Unstuff(uint64_t value) { | 48 | std::pair<int32_t, int32_t> Unstuff(uint64_t value) { |
59 | return {static_cast<int32_t>(value >> 32), | 49 | return {static_cast<int32_t>(value >> 32), |
60 | static_cast<int32_t>(value & ((1ull << 32) - 1))}; | 50 | static_cast<int32_t>(value & ((1ull << 32) - 1))}; |
@@ -115,27 +105,27 @@ void BufferHubQueue::SetupQueue(const QueueInfo& queue_info) { | |||
115 | default_width_ = queue_info.producer_config.default_width; | 105 | default_width_ = queue_info.producer_config.default_width; |
116 | default_height_ = queue_info.producer_config.default_height; | 106 | default_height_ = queue_info.producer_config.default_height; |
117 | default_format_ = queue_info.producer_config.default_format; | 107 | default_format_ = queue_info.producer_config.default_format; |
118 | meta_size_ = queue_info.producer_config.meta_size_bytes; | 108 | user_metadata_size_ = queue_info.producer_config.user_metadata_size; |
119 | id_ = queue_info.id; | 109 | id_ = queue_info.id; |
120 | } | 110 | } |
121 | 111 | ||
122 | std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() { | 112 | std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() { |
123 | if (auto status = CreateConsumerQueueHandle()) | 113 | if (auto status = CreateConsumerQueueHandle(/*silent*/ false)) |
124 | return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take())); | 114 | return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take())); |
125 | else | 115 | else |
126 | return nullptr; | 116 | return nullptr; |
127 | } | 117 | } |
128 | 118 | ||
129 | std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateSilentConsumerQueue() { | 119 | std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateSilentConsumerQueue() { |
130 | if (auto status = CreateConsumerQueueHandle()) | 120 | if (auto status = CreateConsumerQueueHandle(/*silent*/ true)) |
131 | return std::unique_ptr<ConsumerQueue>( | 121 | return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take())); |
132 | new ConsumerQueue(status.take(), true)); | ||
133 | else | 122 | else |
134 | return nullptr; | 123 | return nullptr; |
135 | } | 124 | } |
136 | 125 | ||
137 | Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle() { | 126 | Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle( |
138 | auto status = InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>(); | 127 | bool silent) { |
128 | auto status = InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>(silent); | ||
139 | if (!status) { | 129 | if (!status) { |
140 | ALOGE( | 130 | ALOGE( |
141 | "BufferHubQueue::CreateConsumerQueue: Failed to create consumer queue: " | 131 | "BufferHubQueue::CreateConsumerQueue: Failed to create consumer queue: " |
@@ -148,6 +138,7 @@ Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle() { | |||
148 | } | 138 | } |
149 | 139 | ||
150 | bool BufferHubQueue::WaitForBuffers(int timeout) { | 140 | bool BufferHubQueue::WaitForBuffers(int timeout) { |
141 | ATRACE_NAME("BufferHubQueue::WaitForBuffers"); | ||
151 | std::array<epoll_event, kMaxEvents> events; | 142 | std::array<epoll_event, kMaxEvents> events; |
152 | 143 | ||
153 | // Loop at least once to check for hangups. | 144 | // Loop at least once to check for hangups. |
@@ -178,13 +169,18 @@ bool BufferHubQueue::WaitForBuffers(int timeout) { | |||
178 | const int num_events = ret; | 169 | const int num_events = ret; |
179 | 170 | ||
180 | // A BufferQueue's epoll fd tracks N+1 events, where there are N events, | 171 | // A BufferQueue's epoll fd tracks N+1 events, where there are N events, |
181 | // one for each buffer, in the queue and one extra event for the queue | 172 | // one for each buffer in the queue, and one extra event for the queue |
182 | // client itself. | 173 | // client itself. |
183 | for (int i = 0; i < num_events; i++) { | 174 | for (int i = 0; i < num_events; i++) { |
184 | int32_t event_fd; | 175 | int32_t event_fd; |
185 | int32_t index; | 176 | int32_t index; |
186 | std::tie(event_fd, index) = Unstuff(events[i].data.u64); | 177 | std::tie(event_fd, index) = Unstuff(events[i].data.u64); |
187 | 178 | ||
179 | PDX_TRACE_FORMAT( | ||
180 | "epoll_event|queue_id=%d;num_events=%d;event_index=%d;event_fd=%d;" | ||
181 | "slot=%d|", | ||
182 | id(), num_events, i, event_fd, index); | ||
183 | |||
188 | ALOGD_IF(TRACE, | 184 | ALOGD_IF(TRACE, |
189 | "BufferHubQueue::WaitForBuffers: event %d: event_fd=%d index=%d", | 185 | "BufferHubQueue::WaitForBuffers: event %d: event_fd=%d index=%d", |
190 | i, event_fd, index); | 186 | i, event_fd, index); |
@@ -208,6 +204,7 @@ bool BufferHubQueue::WaitForBuffers(int timeout) { | |||
208 | 204 | ||
209 | Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd, | 205 | Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd, |
210 | int poll_events) { | 206 | int poll_events) { |
207 | ATRACE_NAME("BufferHubQueue::HandleBufferEvent"); | ||
211 | if (!buffers_[slot]) { | 208 | if (!buffers_[slot]) { |
212 | ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot); | 209 | ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot); |
213 | return ErrorStatus(ENOENT); | 210 | return ErrorStatus(ENOENT); |
@@ -221,58 +218,19 @@ Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd, | |||
221 | } | 218 | } |
222 | 219 | ||
223 | const int events = status.get(); | 220 | const int events = status.get(); |
221 | PDX_TRACE_FORMAT( | ||
222 | "buffer|queue_id=%d;buffer_id=%d;slot=%zu;event_fd=%d;poll_events=%x;" | ||
223 | "events=%d|", | ||
224 | id(), buffers_[slot]->id(), slot, event_fd, poll_events, events); | ||
225 | |||
224 | if (events & EPOLLIN) { | 226 | if (events & EPOLLIN) { |
225 | auto entry_status = OnBufferReady(buffers_[slot], slot); | 227 | return Enqueue({buffers_[slot], slot, buffers_[slot]->GetQueueIndex()}); |
226 | if (entry_status.ok() || entry_status.error() == EALREADY) { | ||
227 | // Only enqueue the buffer if it moves to or is already in the state | ||
228 | // requested in OnBufferReady(). | ||
229 | return Enqueue(entry_status.take()); | ||
230 | } else if (entry_status.error() == EBUSY) { | ||
231 | // If the buffer is busy this means that the buffer moved from released to | ||
232 | // posted when a new consumer was created before the ProducerQueue had a | ||
233 | // chance to regain it. This is a valid transition that we have to handle | ||
234 | // because edge triggered poll events latch the ready state even if it is | ||
235 | // later de-asserted -- don't enqueue or print an error log in this case. | ||
236 | } else { | ||
237 | ALOGE( | ||
238 | "BufferHubQueue::HandleBufferEvent: Failed to set buffer ready, " | ||
239 | "queue_id=%d buffer_id=%d: %s", | ||
240 | id(), buffers_[slot]->id(), entry_status.GetErrorMessage().c_str()); | ||
241 | } | ||
242 | } else if (events & EPOLLHUP) { | 228 | } else if (events & EPOLLHUP) { |
243 | // Check to see if the current buffer in the slot hung up. This is a bit of | ||
244 | // paranoia to deal with the epoll set getting out of sync with the buffer | ||
245 | // slots. | ||
246 | auto poll_status = PollEvents(buffers_[slot], POLLIN); | ||
247 | if (!poll_status && poll_status.error() != ETIMEDOUT) { | ||
248 | ALOGE("BufferHubQueue::HandleBufferEvent: Failed to poll buffer: %s", | ||
249 | poll_status.GetErrorMessage().c_str()); | ||
250 | return poll_status.error_status(); | ||
251 | } | ||
252 | |||
253 | const bool hangup_pending = status.ok() && (poll_status.get() & EPOLLHUP); | ||
254 | |||
255 | ALOGW( | 229 | ALOGW( |
256 | "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP event: slot=%zu " | 230 | "BufferHubQueue::HandleBufferEvent: Received EPOLLHUP event: slot=%zu " |
257 | "event_fd=%d buffer_id=%d hangup_pending=%d poll_status=%x", | 231 | "event_fd=%d buffer_id=%d", |
258 | slot, buffers_[slot]->event_fd(), buffers_[slot]->id(), hangup_pending, | 232 | slot, buffers_[slot]->event_fd(), buffers_[slot]->id()); |
259 | poll_status.get()); | 233 | return RemoveBuffer(slot); |
260 | |||
261 | if (hangup_pending) { | ||
262 | return RemoveBuffer(slot); | ||
263 | } else { | ||
264 | // Clean up the bookkeeping for the event fd. This is a bit of paranoia to | ||
265 | // deal with the epoll set getting out of sync with the buffer slots. | ||
266 | // Hitting this path should be very unusual. | ||
267 | const int ret = epoll_fd_.Control(EPOLL_CTL_DEL, event_fd, nullptr); | ||
268 | if (ret < 0) { | ||
269 | ALOGE( | ||
270 | "BufferHubQueue::HandleBufferEvent: Failed to remove fd=%d from " | ||
271 | "epoll set: %s", | ||
272 | event_fd, strerror(-ret)); | ||
273 | return ErrorStatus(-ret); | ||
274 | } | ||
275 | } | ||
276 | } else { | 234 | } else { |
277 | ALOGW( | 235 | ALOGW( |
278 | "BufferHubQueue::HandleBufferEvent: Unknown event, slot=%zu, epoll " | 236 | "BufferHubQueue::HandleBufferEvent: Unknown event, slot=%zu, epoll " |
@@ -284,6 +242,7 @@ Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd, | |||
284 | } | 242 | } |
285 | 243 | ||
286 | Status<void> BufferHubQueue::HandleQueueEvent(int poll_event) { | 244 | Status<void> BufferHubQueue::HandleQueueEvent(int poll_event) { |
245 | ATRACE_NAME("BufferHubQueue::HandleQueueEvent"); | ||
287 | auto status = GetEventMask(poll_event); | 246 | auto status = GetEventMask(poll_event); |
288 | if (!status) { | 247 | if (!status) { |
289 | ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s", | 248 | ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s", |
@@ -330,13 +289,16 @@ Status<void> BufferHubQueue::AddBuffer( | |||
330 | return remove_status.error_status(); | 289 | return remove_status.error_status(); |
331 | } | 290 | } |
332 | 291 | ||
333 | epoll_event event = {.events = EPOLLIN | EPOLLET, | 292 | for (const auto& event_source : buffer->GetEventSources()) { |
334 | .data = {.u64 = Stuff(buffer->event_fd(), slot)}}; | 293 | epoll_event event = {.events = event_source.event_mask | EPOLLET, |
335 | const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, buffer->event_fd(), &event); | 294 | .data = {.u64 = Stuff(buffer->event_fd(), slot)}}; |
336 | if (ret < 0) { | 295 | const int ret = |
337 | ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s", | 296 | epoll_fd_.Control(EPOLL_CTL_ADD, event_source.event_fd, &event); |
338 | strerror(-ret)); | 297 | if (ret < 0) { |
339 | return ErrorStatus(-ret); | 298 | ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s", |
299 | strerror(-ret)); | ||
300 | return ErrorStatus(-ret); | ||
301 | } | ||
340 | } | 302 | } |
341 | 303 | ||
342 | buffers_[slot] = buffer; | 304 | buffers_[slot] = buffer; |
@@ -348,15 +310,16 @@ Status<void> BufferHubQueue::RemoveBuffer(size_t slot) { | |||
348 | ALOGD_IF(TRACE, "BufferHubQueue::RemoveBuffer: slot=%zu", slot); | 310 | ALOGD_IF(TRACE, "BufferHubQueue::RemoveBuffer: slot=%zu", slot); |
349 | 311 | ||
350 | if (buffers_[slot]) { | 312 | if (buffers_[slot]) { |
351 | const int ret = | 313 | for (const auto& event_source : buffers_[slot]->GetEventSources()) { |
352 | epoll_fd_.Control(EPOLL_CTL_DEL, buffers_[slot]->event_fd(), nullptr); | 314 | const int ret = |
353 | if (ret < 0) { | 315 | epoll_fd_.Control(EPOLL_CTL_DEL, event_source.event_fd, nullptr); |
354 | ALOGE( | 316 | if (ret < 0) { |
355 | "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll " | 317 | ALOGE( |
356 | "set: " | 318 | "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll " |
357 | "%s", | 319 | "set: %s", |
358 | strerror(-ret)); | 320 | strerror(-ret)); |
359 | return ErrorStatus(-ret); | 321 | return ErrorStatus(-ret); |
322 | } | ||
360 | } | 323 | } |
361 | 324 | ||
362 | // Trigger OnBufferRemoved callback if registered. | 325 | // Trigger OnBufferRemoved callback if registered. |
@@ -372,7 +335,7 @@ Status<void> BufferHubQueue::RemoveBuffer(size_t slot) { | |||
372 | 335 | ||
373 | Status<void> BufferHubQueue::Enqueue(Entry entry) { | 336 | Status<void> BufferHubQueue::Enqueue(Entry entry) { |
374 | if (!is_full()) { | 337 | if (!is_full()) { |
375 | available_buffers_.Append(std::move(entry)); | 338 | available_buffers_.push(std::move(entry)); |
376 | 339 | ||
377 | // Trigger OnBufferAvailable callback if registered. | 340 | // Trigger OnBufferAvailable callback if registered. |
378 | if (on_buffer_available_) | 341 | if (on_buffer_available_) |
@@ -385,25 +348,26 @@ Status<void> BufferHubQueue::Enqueue(Entry entry) { | |||
385 | } | 348 | } |
386 | } | 349 | } |
387 | 350 | ||
388 | Status<std::shared_ptr<BufferHubBuffer>> BufferHubQueue::Dequeue( | 351 | Status<std::shared_ptr<BufferHubBuffer>> BufferHubQueue::Dequeue(int timeout, |
389 | int timeout, size_t* slot, void* meta, LocalHandle* fence) { | 352 | size_t* slot) { |
390 | ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(), | 353 | ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(), |
391 | timeout); | 354 | timeout); |
392 | 355 | ||
393 | if (!WaitForBuffers(timeout)) | 356 | PDX_TRACE_FORMAT("BufferHubQueue::Dequeue|count=%zu|", count()); |
394 | return ErrorStatus(ETIMEDOUT); | 357 | |
358 | if (count() == 0) { | ||
359 | if (!WaitForBuffers(timeout)) | ||
360 | return ErrorStatus(ETIMEDOUT); | ||
361 | } | ||
395 | 362 | ||
396 | auto& entry = available_buffers_.Front(); | 363 | auto& entry = available_buffers_.top(); |
364 | PDX_TRACE_FORMAT("buffer|buffer_id=%d;slot=%zu|", entry.buffer->id(), | ||
365 | entry.slot); | ||
397 | 366 | ||
398 | std::shared_ptr<BufferHubBuffer> buffer = std::move(entry.buffer); | 367 | std::shared_ptr<BufferHubBuffer> buffer = std::move(entry.buffer); |
399 | *slot = entry.slot; | 368 | *slot = entry.slot; |
400 | *fence = std::move(entry.fence); | ||
401 | if (meta && entry.metadata) { | ||
402 | std::copy(entry.metadata.get(), entry.metadata.get() + meta_size_, | ||
403 | reinterpret_cast<uint8_t*>(meta)); | ||
404 | } | ||
405 | 369 | ||
406 | available_buffers_.PopFront(); | 370 | available_buffers_.pop(); |
407 | 371 | ||
408 | return {std::move(buffer)}; | 372 | return {std::move(buffer)}; |
409 | } | 373 | } |
@@ -419,7 +383,8 @@ void BufferHubQueue::SetBufferRemovedCallback(BufferRemovedCallback callback) { | |||
419 | 383 | ||
420 | pdx::Status<void> BufferHubQueue::FreeAllBuffers() { | 384 | pdx::Status<void> BufferHubQueue::FreeAllBuffers() { |
421 | // Clear all available buffers. | 385 | // Clear all available buffers. |
422 | available_buffers_.Clear(); | 386 | while (!available_buffers_.empty()) |
387 | available_buffers_.pop(); | ||
423 | 388 | ||
424 | pdx::Status<void> last_error; // No error. | 389 | pdx::Status<void> last_error; // No error. |
425 | // Clear all buffers this producer queue is tracking. | 390 | // Clear all buffers this producer queue is tracking. |
@@ -429,7 +394,7 @@ pdx::Status<void> BufferHubQueue::FreeAllBuffers() { | |||
429 | if (!status) { | 394 | if (!status) { |
430 | ALOGE( | 395 | ALOGE( |
431 | "ProducerQueue::FreeAllBuffers: Failed to remove buffer at " | 396 | "ProducerQueue::FreeAllBuffers: Failed to remove buffer at " |
432 | "slot=%d.", | 397 | "slot=%zu.", |
433 | slot); | 398 | slot); |
434 | last_error = status.error_status(); | 399 | last_error = status.error_status(); |
435 | } | 400 | } |
@@ -548,7 +513,7 @@ Status<void> ProducerQueue::AddBuffer( | |||
548 | if (!status) | 513 | if (!status) |
549 | return status; | 514 | return status; |
550 | 515 | ||
551 | return Enqueue(buffer, slot); | 516 | return BufferHubQueue::Enqueue({buffer, slot, 0ULL}); |
552 | } | 517 | } |
553 | 518 | ||
554 | Status<void> ProducerQueue::RemoveBuffer(size_t slot) { | 519 | Status<void> ProducerQueue::RemoveBuffer(size_t slot) { |
@@ -565,40 +530,33 @@ Status<void> ProducerQueue::RemoveBuffer(size_t slot) { | |||
565 | 530 | ||
566 | Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue( | 531 | Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue( |
567 | int timeout, size_t* slot, LocalHandle* release_fence) { | 532 | int timeout, size_t* slot, LocalHandle* release_fence) { |
568 | if (slot == nullptr || release_fence == nullptr) { | 533 | DvrNativeBufferMetadata canonical_meta; |
569 | ALOGE("ProducerQueue::Dequeue: Invalid parameter: slot=%p release_fence=%p", | 534 | return Dequeue(timeout, slot, &canonical_meta, release_fence); |
570 | slot, release_fence); | ||
571 | return ErrorStatus(EINVAL); | ||
572 | } | ||
573 | |||
574 | auto buffer_status = | ||
575 | BufferHubQueue::Dequeue(timeout, slot, nullptr, release_fence); | ||
576 | if (!buffer_status) | ||
577 | return buffer_status.error_status(); | ||
578 | |||
579 | return {std::static_pointer_cast<BufferProducer>(buffer_status.take())}; | ||
580 | } | 535 | } |
581 | 536 | ||
582 | Status<BufferHubQueue::Entry> ProducerQueue::OnBufferReady( | 537 | pdx::Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue( |
583 | const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) { | 538 | int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta, |
584 | ALOGD_IF(TRACE, | 539 | pdx::LocalHandle* release_fence) { |
585 | "ProducerQueue::OnBufferReady: queue_id=%d buffer_id=%d slot=%zu", | 540 | ATRACE_NAME("ProducerQueue::Dequeue"); |
586 | id(), buffer->id(), slot); | 541 | if (slot == nullptr || out_meta == nullptr || release_fence == nullptr) { |
542 | ALOGE("ProducerQueue::Dequeue: Invalid parameter."); | ||
543 | return ErrorStatus(EINVAL); | ||
544 | } | ||
587 | 545 | ||
588 | // Avoid taking a transient reference, buffer is valid for the duration of | 546 | auto status = BufferHubQueue::Dequeue(timeout, slot); |
589 | // this method call. | 547 | if (!status) |
590 | auto* producer_buffer = static_cast<BufferProducer*>(buffer.get()); | 548 | return status.error_status(); |
591 | LocalHandle release_fence; | ||
592 | 549 | ||
593 | const int ret = producer_buffer->Gain(&release_fence); | 550 | auto buffer = std::static_pointer_cast<BufferProducer>(status.take()); |
594 | if (ret < 0) | 551 | const int ret = buffer->GainAsync(out_meta, release_fence); |
552 | if (ret < 0 && ret != -EALREADY) | ||
595 | return ErrorStatus(-ret); | 553 | return ErrorStatus(-ret); |
596 | else | 554 | |
597 | return {{buffer, nullptr, std::move(release_fence), slot}}; | 555 | return {std::move(buffer)}; |
598 | } | 556 | } |
599 | 557 | ||
600 | ConsumerQueue::ConsumerQueue(LocalChannelHandle handle, bool ignore_on_import) | 558 | ConsumerQueue::ConsumerQueue(LocalChannelHandle handle) |
601 | : BufferHubQueue(std::move(handle)), ignore_on_import_(ignore_on_import) { | 559 | : BufferHubQueue(std::move(handle)) { |
602 | auto status = ImportQueue(); | 560 | auto status = ImportQueue(); |
603 | if (!status) { | 561 | if (!status) { |
604 | ALOGE("ConsumerQueue::ConsumerQueue: Failed to import queue: %s", | 562 | ALOGE("ConsumerQueue::ConsumerQueue: Failed to import queue: %s", |
@@ -619,9 +577,17 @@ ConsumerQueue::ConsumerQueue(LocalChannelHandle handle, bool ignore_on_import) | |||
619 | Status<size_t> ConsumerQueue::ImportBuffers() { | 577 | Status<size_t> ConsumerQueue::ImportBuffers() { |
620 | auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>(); | 578 | auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>(); |
621 | if (!status) { | 579 | if (!status) { |
622 | ALOGE("ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s", | 580 | if (status.error() == EBADR) { |
581 | ALOGI( | ||
582 | "ConsumerQueue::ImportBuffers: Queue is silent, no buffers " | ||
583 | "imported."); | ||
584 | return {0}; | ||
585 | } else { | ||
586 | ALOGE( | ||
587 | "ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s", | ||
623 | status.GetErrorMessage().c_str()); | 588 | status.GetErrorMessage().c_str()); |
624 | return status.error_status(); | 589 | return status.error_status(); |
590 | } | ||
625 | } | 591 | } |
626 | 592 | ||
627 | int ret; | 593 | int ret; |
@@ -642,22 +608,6 @@ Status<size_t> ConsumerQueue::ImportBuffers() { | |||
642 | continue; | 608 | continue; |
643 | } | 609 | } |
644 | 610 | ||
645 | // Setup ignore state before adding buffer to the queue. | ||
646 | if (ignore_on_import_) { | ||
647 | ALOGD_IF(TRACE, | ||
648 | "ConsumerQueue::ImportBuffers: Setting buffer to ignored state: " | ||
649 | "buffer_id=%d", | ||
650 | buffer_consumer->id()); | ||
651 | ret = buffer_consumer->SetIgnore(true); | ||
652 | if (ret < 0) { | ||
653 | ALOGE( | ||
654 | "ConsumerQueue::ImportBuffers: Failed to set ignored state on " | ||
655 | "imported buffer buffer_id=%d: %s", | ||
656 | buffer_consumer->id(), strerror(-ret)); | ||
657 | last_error = ErrorStatus(-ret); | ||
658 | } | ||
659 | } | ||
660 | |||
661 | auto add_status = | 611 | auto add_status = |
662 | AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second); | 612 | AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second); |
663 | if (!add_status) { | 613 | if (!add_status) { |
@@ -685,7 +635,7 @@ Status<void> ConsumerQueue::AddBuffer( | |||
685 | 635 | ||
686 | // Check to see if the buffer is already signaled. This is necessary to catch | 636 | // Check to see if the buffer is already signaled. This is necessary to catch |
687 | // cases where buffers are already available; epoll edge triggered mode does | 637 | // cases where buffers are already available; epoll edge triggered mode does |
688 | // not fire until and edge transition when adding new buffers to the epoll | 638 | // not fire until an edge transition when adding new buffers to the epoll |
689 | // set. Note that we only poll the fd events because HandleBufferEvent() takes | 639 | // set. Note that we only poll the fd events because HandleBufferEvent() takes |
690 | // care of checking the translated buffer events. | 640 | // care of checking the translated buffer events. |
691 | auto poll_status = PollEvents(buffer->event_fd(), POLLIN); | 641 | auto poll_status = PollEvents(buffer->event_fd(), POLLIN); |
@@ -703,51 +653,53 @@ Status<void> ConsumerQueue::AddBuffer( | |||
703 | } | 653 | } |
704 | 654 | ||
705 | Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue( | 655 | Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue( |
706 | int timeout, size_t* slot, void* meta, size_t meta_size, | 656 | int timeout, size_t* slot, void* meta, size_t user_metadata_size, |
707 | LocalHandle* acquire_fence) { | 657 | LocalHandle* acquire_fence) { |
708 | if (meta_size != meta_size_) { | 658 | if (user_metadata_size != user_metadata_size_) { |
709 | ALOGE( | 659 | ALOGE( |
710 | "ConsumerQueue::Dequeue: Metadata size (%zu) for the dequeuing buffer " | 660 | "ConsumerQueue::Dequeue: Metadata size (%zu) for the dequeuing buffer " |
711 | "does not match metadata size (%zu) for the queue.", | 661 | "does not match metadata size (%zu) for the queue.", |
712 | meta_size, meta_size_); | 662 | user_metadata_size, user_metadata_size_); |
713 | return ErrorStatus(EINVAL); | 663 | return ErrorStatus(EINVAL); |
714 | } | 664 | } |
715 | 665 | ||
716 | if (slot == nullptr || acquire_fence == nullptr) { | 666 | DvrNativeBufferMetadata canonical_meta; |
717 | ALOGE( | 667 | auto status = Dequeue(timeout, slot, &canonical_meta, acquire_fence); |
718 | "ConsumerQueue::Dequeue: Invalid parameter: slot=%p meta=%p " | 668 | if (!status) |
719 | "acquire_fence=%p", | 669 | return status.error_status(); |
720 | slot, meta, acquire_fence); | ||
721 | return ErrorStatus(EINVAL); | ||
722 | } | ||
723 | 670 | ||
724 | auto buffer_status = | 671 | if (meta && user_metadata_size) { |
725 | BufferHubQueue::Dequeue(timeout, slot, meta, acquire_fence); | 672 | void* metadata_src = |
726 | if (!buffer_status) | 673 | reinterpret_cast<void*>(canonical_meta.user_metadata_ptr); |
727 | return buffer_status.error_status(); | 674 | if (metadata_src) { |
675 | memcpy(meta, metadata_src, user_metadata_size); | ||
676 | } else { | ||
677 | ALOGW("ConsumerQueue::Dequeue: no user-defined metadata."); | ||
678 | } | ||
679 | } | ||
728 | 680 | ||
729 | return {std::static_pointer_cast<BufferConsumer>(buffer_status.take())}; | 681 | return status; |
730 | } | 682 | } |
731 | 683 | ||
732 | Status<BufferHubQueue::Entry> ConsumerQueue::OnBufferReady( | 684 | Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue( |
733 | const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) { | 685 | int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta, |
734 | ALOGD_IF(TRACE, | 686 | pdx::LocalHandle* acquire_fence) { |
735 | "ConsumerQueue::OnBufferReady: queue_id=%d buffer_id=%d slot=%zu", | 687 | ATRACE_NAME("ConsumerQueue::Dequeue"); |
736 | id(), buffer->id(), slot); | 688 | if (slot == nullptr || out_meta == nullptr || acquire_fence == nullptr) { |
689 | ALOGE("ConsumerQueue::Dequeue: Invalid parameter."); | ||
690 | return ErrorStatus(EINVAL); | ||
691 | } | ||
737 | 692 | ||
738 | // Avoid taking a transient reference, buffer is valid for the duration of | 693 | auto status = BufferHubQueue::Dequeue(timeout, slot); |
739 | // this method call. | 694 | if (!status) |
740 | auto* consumer_buffer = static_cast<BufferConsumer*>(buffer.get()); | 695 | return status.error_status(); |
741 | std::unique_ptr<uint8_t[]> metadata(meta_size_ ? new uint8_t[meta_size_] | ||
742 | : nullptr); | ||
743 | LocalHandle acquire_fence; | ||
744 | 696 | ||
745 | const int ret = | 697 | auto buffer = std::static_pointer_cast<BufferConsumer>(status.take()); |
746 | consumer_buffer->Acquire(&acquire_fence, metadata.get(), meta_size_); | 698 | const int ret = buffer->AcquireAsync(out_meta, acquire_fence); |
747 | if (ret < 0) | 699 | if (ret < 0) |
748 | return ErrorStatus(-ret); | 700 | return ErrorStatus(-ret); |
749 | else | 701 | |
750 | return {{buffer, std::move(metadata), std::move(acquire_fence), slot}}; | 702 | return {std::move(buffer)}; |
751 | } | 703 | } |
752 | 704 | ||
753 | Status<void> ConsumerQueue::OnBufferAllocated() { | 705 | Status<void> ConsumerQueue::OnBufferAllocated() { |
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp index 53eed8924..221bc4f9d 100644 --- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp +++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp | |||
@@ -328,7 +328,7 @@ status_t BufferHubQueueProducer::queueBuffer(int slot, | |||
328 | 328 | ||
329 | LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1); | 329 | LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1); |
330 | 330 | ||
331 | DvrNativeBufferMetadata meta_data = {}; | 331 | DvrNativeBufferMetadata meta_data; |
332 | meta_data.timestamp = timestamp; | 332 | meta_data.timestamp = timestamp; |
333 | meta_data.is_auto_timestamp = static_cast<int32_t>(is_auto_timestamp); | 333 | meta_data.is_auto_timestamp = static_cast<int32_t>(is_auto_timestamp); |
334 | meta_data.dataspace = static_cast<int32_t>(dataspace); | 334 | meta_data.dataspace = static_cast<int32_t>(dataspace); |
@@ -339,7 +339,7 @@ status_t BufferHubQueueProducer::queueBuffer(int slot, | |||
339 | meta_data.scaling_mode = static_cast<int32_t>(scaling_mode); | 339 | meta_data.scaling_mode = static_cast<int32_t>(scaling_mode); |
340 | meta_data.transform = static_cast<int32_t>(transform); | 340 | meta_data.transform = static_cast<int32_t>(transform); |
341 | 341 | ||
342 | buffer_producer->Post(fence_fd, &meta_data, sizeof(meta_data)); | 342 | buffer_producer->PostAsync(&meta_data, fence_fd); |
343 | buffers_[slot].mBufferState.queue(); | 343 | buffers_[slot].mBufferState.queue(); |
344 | 344 | ||
345 | output->width = buffer_producer->width(); | 345 | output->width = buffer_producer->width(); |
@@ -384,7 +384,7 @@ status_t BufferHubQueueProducer::cancelBuffer(int slot, | |||
384 | } | 384 | } |
385 | 385 | ||
386 | auto buffer_producer = buffers_[slot].mBufferProducer; | 386 | auto buffer_producer = buffers_[slot].mBufferProducer; |
387 | queue_->Enqueue(buffer_producer, slot); | 387 | queue_->Enqueue(buffer_producer, slot, 0ULL); |
388 | buffers_[slot].mBufferState.cancel(); | 388 | buffers_[slot].mBufferState.cancel(); |
389 | buffers_[slot].mFence = fence; | 389 | buffers_[slot].mFence = fence; |
390 | ALOGD_IF(TRACE, "cancelBuffer: slot %d", slot); | 390 | ALOGD_IF(TRACE, "cancelBuffer: slot %d", slot); |
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h index 0699fefd3..6962d6c9f 100644 --- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h +++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h | |||
@@ -5,12 +5,13 @@ | |||
5 | 5 | ||
6 | #include <pdx/client.h> | 6 | #include <pdx/client.h> |
7 | #include <pdx/status.h> | 7 | #include <pdx/status.h> |
8 | #include <private/dvr/bufferhub_rpc.h> | ||
9 | #include <private/dvr/buffer_hub_client.h> | 8 | #include <private/dvr/buffer_hub_client.h> |
9 | #include <private/dvr/bufferhub_rpc.h> | ||
10 | #include <private/dvr/epoll_file_descriptor.h> | 10 | #include <private/dvr/epoll_file_descriptor.h> |
11 | #include <private/dvr/ring_buffer.h> | 11 | #include <private/dvr/ring_buffer.h> |
12 | 12 | ||
13 | #include <memory> | 13 | #include <memory> |
14 | #include <queue> | ||
14 | #include <vector> | 15 | #include <vector> |
15 | 16 | ||
16 | namespace android { | 17 | namespace android { |
@@ -50,19 +51,22 @@ class BufferHubQueue : public pdx::Client { | |||
50 | uint32_t default_format() const { return default_format_; } | 51 | uint32_t default_format() const { return default_format_; } |
51 | 52 | ||
52 | // Creates a new consumer in handle form for immediate transport over RPC. | 53 | // Creates a new consumer in handle form for immediate transport over RPC. |
53 | pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(); | 54 | pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle( |
55 | bool silent = false); | ||
54 | 56 | ||
55 | // Returns the number of buffers avaiable for dequeue. | 57 | // Returns the number of buffers avaiable for dequeue. |
56 | size_t count() const { return available_buffers_.GetSize(); } | 58 | size_t count() const { return available_buffers_.size(); } |
57 | 59 | ||
58 | // Returns the total number of buffers that the queue is tracking. | 60 | // Returns the total number of buffers that the queue is tracking. |
59 | size_t capacity() const { return capacity_; } | 61 | size_t capacity() const { return capacity_; } |
60 | 62 | ||
61 | // Returns the size of metadata structure associated with this queue. | 63 | // Returns the size of metadata structure associated with this queue. |
62 | size_t metadata_size() const { return meta_size_; } | 64 | size_t metadata_size() const { return user_metadata_size_; } |
63 | 65 | ||
64 | // Returns whether the buffer queue is full. | 66 | // Returns whether the buffer queue is full. |
65 | bool is_full() const { return available_buffers_.IsFull(); } | 67 | bool is_full() const { |
68 | return available_buffers_.size() >= kMaxQueueCapacity; | ||
69 | } | ||
66 | 70 | ||
67 | explicit operator bool() const { return epoll_fd_.IsValid(); } | 71 | explicit operator bool() const { return epoll_fd_.IsValid(); } |
68 | 72 | ||
@@ -136,8 +140,8 @@ class BufferHubQueue : public pdx::Client { | |||
136 | // block. Specifying a timeout of -1 causes Dequeue() to block indefinitely, | 140 | // block. Specifying a timeout of -1 causes Dequeue() to block indefinitely, |
137 | // while specifying a timeout equal to zero cause Dequeue() to return | 141 | // while specifying a timeout equal to zero cause Dequeue() to return |
138 | // immediately, even if no buffers are available. | 142 | // immediately, even if no buffers are available. |
139 | pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue( | 143 | pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue(int timeout, |
140 | int timeout, size_t* slot, void* meta, pdx::LocalHandle* fence); | 144 | size_t* slot); |
141 | 145 | ||
142 | // Waits for buffers to become available and adds them to the available queue. | 146 | // Waits for buffers to become available and adds them to the available queue. |
143 | bool WaitForBuffers(int timeout); | 147 | bool WaitForBuffers(int timeout); |
@@ -150,8 +154,9 @@ class BufferHubQueue : public pdx::Client { | |||
150 | // per-buffer data. | 154 | // per-buffer data. |
151 | struct Entry { | 155 | struct Entry { |
152 | Entry() : slot(0) {} | 156 | Entry() : slot(0) {} |
153 | Entry(const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) | 157 | Entry(const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot, |
154 | : buffer(buffer), slot(slot) {} | 158 | uint64_t index) |
159 | : buffer(buffer), slot(slot), index(index) {} | ||
155 | Entry(const std::shared_ptr<BufferHubBuffer>& buffer, | 160 | Entry(const std::shared_ptr<BufferHubBuffer>& buffer, |
156 | std::unique_ptr<uint8_t[]> metadata, pdx::LocalHandle fence, | 161 | std::unique_ptr<uint8_t[]> metadata, pdx::LocalHandle fence, |
157 | size_t slot) | 162 | size_t slot) |
@@ -166,20 +171,24 @@ class BufferHubQueue : public pdx::Client { | |||
166 | std::unique_ptr<uint8_t[]> metadata; | 171 | std::unique_ptr<uint8_t[]> metadata; |
167 | pdx::LocalHandle fence; | 172 | pdx::LocalHandle fence; |
168 | size_t slot; | 173 | size_t slot; |
174 | uint64_t index; | ||
175 | }; | ||
176 | |||
177 | struct EntryComparator { | ||
178 | bool operator()(const Entry& lhs, const Entry& rhs) { | ||
179 | return lhs.index > rhs.index; | ||
180 | } | ||
169 | }; | 181 | }; |
170 | 182 | ||
171 | // Enqueues a buffer to the available list (Gained for producer or Acquireed | 183 | // Enqueues a buffer to the available list (Gained for producer or Acquireed |
172 | // for consumer). | 184 | // for consumer). |
173 | pdx::Status<void> Enqueue(Entry entry); | 185 | pdx::Status<void> Enqueue(Entry entry); |
174 | 186 | ||
175 | virtual pdx::Status<Entry> OnBufferReady( | ||
176 | const std::shared_ptr<BufferHubBuffer>& buf, size_t slot) = 0; | ||
177 | |||
178 | // Called when a buffer is allocated remotely. | 187 | // Called when a buffer is allocated remotely. |
179 | virtual pdx::Status<void> OnBufferAllocated() { return {}; } | 188 | virtual pdx::Status<void> OnBufferAllocated() { return {}; } |
180 | 189 | ||
181 | // Size of the metadata that buffers in this queue cary. | 190 | // Size of the metadata that buffers in this queue cary. |
182 | size_t meta_size_{0}; | 191 | size_t user_metadata_size_{0}; |
183 | 192 | ||
184 | private: | 193 | private: |
185 | void Initialize(); | 194 | void Initialize(); |
@@ -226,7 +235,9 @@ class BufferHubQueue : public pdx::Client { | |||
226 | std::array<std::shared_ptr<BufferHubBuffer>, kMaxQueueCapacity> buffers_; | 235 | std::array<std::shared_ptr<BufferHubBuffer>, kMaxQueueCapacity> buffers_; |
227 | 236 | ||
228 | // Buffers and related data that are available for dequeue. | 237 | // Buffers and related data that are available for dequeue. |
229 | RingBuffer<Entry> available_buffers_{kMaxQueueCapacity}; | 238 | // RingBuffer<Entry> available_buffers_{kMaxQueueCapacity}; |
239 | std::priority_queue<Entry, std::vector<Entry>, EntryComparator> | ||
240 | available_buffers_; | ||
230 | 241 | ||
231 | // Keeps track with how many buffers have been added into the queue. | 242 | // Keeps track with how many buffers have been added into the queue. |
232 | size_t capacity_{0}; | 243 | size_t capacity_{0}; |
@@ -316,11 +327,14 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { | |||
316 | // to the consumer side. | 327 | // to the consumer side. |
317 | pdx::Status<std::shared_ptr<BufferProducer>> Dequeue( | 328 | pdx::Status<std::shared_ptr<BufferProducer>> Dequeue( |
318 | int timeout, size_t* slot, pdx::LocalHandle* release_fence); | 329 | int timeout, size_t* slot, pdx::LocalHandle* release_fence); |
330 | pdx::Status<std::shared_ptr<BufferProducer>> Dequeue( | ||
331 | int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta, | ||
332 | pdx::LocalHandle* release_fence); | ||
319 | 333 | ||
320 | // Enqueues a producer buffer in the queue. | 334 | // Enqueues a producer buffer in the queue. |
321 | pdx::Status<void> Enqueue(const std::shared_ptr<BufferProducer>& buffer, | 335 | pdx::Status<void> Enqueue(const std::shared_ptr<BufferProducer>& buffer, |
322 | size_t slot) { | 336 | size_t slot, uint64_t index) { |
323 | return BufferHubQueue::Enqueue({buffer, slot}); | 337 | return BufferHubQueue::Enqueue({buffer, slot, index}); |
324 | } | 338 | } |
325 | 339 | ||
326 | private: | 340 | private: |
@@ -331,9 +345,6 @@ class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> { | |||
331 | // arguments as the constructors. | 345 | // arguments as the constructors. |
332 | explicit ProducerQueue(pdx::LocalChannelHandle handle); | 346 | explicit ProducerQueue(pdx::LocalChannelHandle handle); |
333 | ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage); | 347 | ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage); |
334 | |||
335 | pdx::Status<Entry> OnBufferReady( | ||
336 | const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override; | ||
337 | }; | 348 | }; |
338 | 349 | ||
339 | class ConsumerQueue : public BufferHubQueue { | 350 | class ConsumerQueue : public BufferHubQueue { |
@@ -352,10 +363,9 @@ class ConsumerQueue : public BufferHubQueue { | |||
352 | // used to avoid participation in the buffer lifecycle by a consumer queue | 363 | // used to avoid participation in the buffer lifecycle by a consumer queue |
353 | // that is only used to spawn other consumer queues, such as in an | 364 | // that is only used to spawn other consumer queues, such as in an |
354 | // intermediate service. | 365 | // intermediate service. |
355 | static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle, | 366 | static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle) { |
356 | bool ignore_on_import = false) { | ||
357 | return std::unique_ptr<ConsumerQueue>( | 367 | return std::unique_ptr<ConsumerQueue>( |
358 | new ConsumerQueue(std::move(handle), ignore_on_import)); | 368 | new ConsumerQueue(std::move(handle))); |
359 | } | 369 | } |
360 | 370 | ||
361 | // Import newly created buffers from the service side. | 371 | // Import newly created buffers from the service side. |
@@ -379,13 +389,16 @@ class ConsumerQueue : public BufferHubQueue { | |||
379 | } | 389 | } |
380 | 390 | ||
381 | pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue( | 391 | pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue( |
382 | int timeout, size_t* slot, void* meta, size_t meta_size, | 392 | int timeout, size_t* slot, void* meta, size_t user_metadata_size, |
393 | pdx::LocalHandle* acquire_fence); | ||
394 | pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue( | ||
395 | int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta, | ||
383 | pdx::LocalHandle* acquire_fence); | 396 | pdx::LocalHandle* acquire_fence); |
384 | 397 | ||
385 | private: | 398 | private: |
386 | friend BufferHubQueue; | 399 | friend BufferHubQueue; |
387 | 400 | ||
388 | ConsumerQueue(pdx::LocalChannelHandle handle, bool ignore_on_import = false); | 401 | ConsumerQueue(pdx::LocalChannelHandle handle); |
389 | 402 | ||
390 | // Add a consumer buffer to populate the queue. Once added, a consumer buffer | 403 | // Add a consumer buffer to populate the queue. Once added, a consumer buffer |
391 | // is NOT available to use until the producer side |Post| it. |WaitForBuffers| | 404 | // is NOT available to use until the producer side |Post| it. |WaitForBuffers| |
@@ -394,14 +407,7 @@ class ConsumerQueue : public BufferHubQueue { | |||
394 | pdx::Status<void> AddBuffer(const std::shared_ptr<BufferConsumer>& buffer, | 407 | pdx::Status<void> AddBuffer(const std::shared_ptr<BufferConsumer>& buffer, |
395 | size_t slot); | 408 | size_t slot); |
396 | 409 | ||
397 | pdx::Status<Entry> OnBufferReady( | ||
398 | const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override; | ||
399 | |||
400 | pdx::Status<void> OnBufferAllocated() override; | 410 | pdx::Status<void> OnBufferAllocated() override; |
401 | |||
402 | // Flag indicating that imported (consumer) buffers should be ignored when | ||
403 | // imported to avoid participating in the buffer ownership flow. | ||
404 | bool ignore_on_import_; | ||
405 | }; | 411 | }; |
406 | 412 | ||
407 | } // namespace dvr | 413 | } // namespace dvr |
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp index 865573caf..8bd1ef141 100644 --- a/libs/vr/libbufferhubqueue/tests/Android.bp +++ b/libs/vr/libbufferhubqueue/tests/Android.bp | |||
@@ -1,4 +1,7 @@ | |||
1 | 1 | ||
2 | header_libraries = [ | ||
3 | "libdvr_headers", | ||
4 | ] | ||
2 | 5 | ||
3 | shared_libraries = [ | 6 | shared_libraries = [ |
4 | "libbase", | 7 | "libbase", |
@@ -21,6 +24,7 @@ static_libraries = [ | |||
21 | 24 | ||
22 | cc_test { | 25 | cc_test { |
23 | srcs: ["buffer_hub_queue-test.cpp"], | 26 | srcs: ["buffer_hub_queue-test.cpp"], |
27 | header_libs: header_libraries, | ||
24 | static_libs: static_libraries, | 28 | static_libs: static_libraries, |
25 | shared_libs: shared_libraries, | 29 | shared_libs: shared_libraries, |
26 | cflags: [ | 30 | cflags: [ |
@@ -35,6 +39,7 @@ cc_test { | |||
35 | 39 | ||
36 | cc_test { | 40 | cc_test { |
37 | srcs: ["buffer_hub_queue_producer-test.cpp"], | 41 | srcs: ["buffer_hub_queue_producer-test.cpp"], |
42 | header_libs: header_libraries, | ||
38 | static_libs: static_libraries, | 43 | static_libs: static_libraries, |
39 | shared_libs: shared_libraries, | 44 | shared_libs: shared_libraries, |
40 | cflags: [ | 45 | cflags: [ |
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp index 7581a065b..8a72531ed 100644 --- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp +++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp | |||
@@ -3,6 +3,8 @@ | |||
3 | #include <private/dvr/buffer_hub_queue_client.h> | 3 | #include <private/dvr/buffer_hub_queue_client.h> |
4 | 4 | ||
5 | #include <gtest/gtest.h> | 5 | #include <gtest/gtest.h> |
6 | #include <poll.h> | ||
7 | #include <sys/eventfd.h> | ||
6 | 8 | ||
7 | #include <vector> | 9 | #include <vector> |
8 | 10 | ||
@@ -46,9 +48,9 @@ class BufferHubQueueTest : public ::testing::Test { | |||
46 | 48 | ||
47 | void AllocateBuffer(size_t* slot_out = nullptr) { | 49 | void AllocateBuffer(size_t* slot_out = nullptr) { |
48 | // Create producer buffer. | 50 | // Create producer buffer. |
49 | auto status = producer_queue_->AllocateBuffer( | 51 | auto status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, |
50 | kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, | 52 | kBufferLayerCount, |
51 | kBufferUsage); | 53 | kBufferFormat, kBufferUsage); |
52 | 54 | ||
53 | ASSERT_TRUE(status.ok()); | 55 | ASSERT_TRUE(status.ok()); |
54 | size_t slot = status.take(); | 56 | size_t slot = status.take(); |
@@ -56,6 +58,23 @@ class BufferHubQueueTest : public ::testing::Test { | |||
56 | *slot_out = slot; | 58 | *slot_out = slot; |
57 | } | 59 | } |
58 | 60 | ||
61 | bool WaitAndHandleOnce(BufferHubQueue* queue, int timeout_ms) { | ||
62 | pollfd pfd{queue->queue_fd(), POLLIN, 0}; | ||
63 | int ret; | ||
64 | do { | ||
65 | ret = poll(&pfd, 1, timeout_ms); | ||
66 | } while (ret == -1 && errno == EINTR); | ||
67 | |||
68 | if (ret < 0) { | ||
69 | ALOGW("Failed to poll queue %d's event fd, error: %s.", queue->id(), | ||
70 | strerror(errno)); | ||
71 | return false; | ||
72 | } else if (ret == 0) { | ||
73 | return false; | ||
74 | } | ||
75 | return queue->HandleQueueEvents(); | ||
76 | } | ||
77 | |||
59 | protected: | 78 | protected: |
60 | ProducerQueueConfigBuilder config_builder_; | 79 | ProducerQueueConfigBuilder config_builder_; |
61 | std::unique_ptr<ProducerQueue> producer_queue_; | 80 | std::unique_ptr<ProducerQueue> producer_queue_; |
@@ -75,7 +94,7 @@ TEST_F(BufferHubQueueTest, TestDequeue) { | |||
75 | for (size_t i = 0; i < nb_dequeue_times; i++) { | 94 | for (size_t i = 0; i < nb_dequeue_times; i++) { |
76 | size_t slot; | 95 | size_t slot; |
77 | LocalHandle fence; | 96 | LocalHandle fence; |
78 | auto p1_status = producer_queue_->Dequeue(0, &slot, &fence); | 97 | auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); |
79 | ASSERT_TRUE(p1_status.ok()); | 98 | ASSERT_TRUE(p1_status.ok()); |
80 | auto p1 = p1_status.take(); | 99 | auto p1 = p1_status.take(); |
81 | ASSERT_NE(nullptr, p1); | 100 | ASSERT_NE(nullptr, p1); |
@@ -113,31 +132,26 @@ TEST_F(BufferHubQueueTest, TestProducerConsumer) { | |||
113 | // Dequeue returns timeout since no buffer is ready to consumer, but | 132 | // Dequeue returns timeout since no buffer is ready to consumer, but |
114 | // this implicitly triggers buffer import and bump up |capacity|. | 133 | // this implicitly triggers buffer import and bump up |capacity|. |
115 | LocalHandle fence; | 134 | LocalHandle fence; |
116 | auto status = consumer_queue_->Dequeue(0, &slot, &seq, &fence); | 135 | auto status = consumer_queue_->Dequeue(100, &slot, &seq, &fence); |
117 | ASSERT_FALSE(status.ok()); | 136 | ASSERT_FALSE(status.ok()); |
118 | ASSERT_EQ(ETIMEDOUT, status.error()); | 137 | ASSERT_EQ(ETIMEDOUT, status.error()); |
119 | ASSERT_EQ(consumer_queue_->capacity(), i + 1); | 138 | ASSERT_EQ(consumer_queue_->capacity(), i + 1); |
120 | } | 139 | } |
121 | 140 | ||
122 | // Use /dev/zero as a stand-in for a fence. As long as BufferHub does not need | 141 | // Use eventfd as a stand-in for a fence. |
123 | // to merge fences, which only happens when multiple consumers release the | 142 | LocalHandle post_fence(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); |
124 | // same buffer with release fences, the file object should simply pass | ||
125 | // through. | ||
126 | LocalHandle post_fence("/dev/zero", O_RDONLY); | ||
127 | struct stat post_fence_stat; | ||
128 | ASSERT_EQ(0, fstat(post_fence.Get(), &post_fence_stat)); | ||
129 | 143 | ||
130 | for (size_t i = 0; i < kBufferCount; i++) { | 144 | for (size_t i = 0; i < kBufferCount; i++) { |
131 | LocalHandle fence; | 145 | LocalHandle fence; |
132 | 146 | ||
133 | // First time there is no buffer available to dequeue. | 147 | // First time there is no buffer available to dequeue. |
134 | auto consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence); | 148 | auto consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence); |
135 | ASSERT_FALSE(consumer_status.ok()); | 149 | ASSERT_FALSE(consumer_status.ok()); |
136 | ASSERT_EQ(ETIMEDOUT, consumer_status.error()); | 150 | ASSERT_EQ(ETIMEDOUT, consumer_status.error()); |
137 | 151 | ||
138 | // Make sure Producer buffer is POSTED so that it's ready to Accquire | 152 | // Make sure Producer buffer is POSTED so that it's ready to Accquire |
139 | // in the consumer's Dequeue() function. | 153 | // in the consumer's Dequeue() function. |
140 | auto producer_status = producer_queue_->Dequeue(0, &slot, &fence); | 154 | auto producer_status = producer_queue_->Dequeue(100, &slot, &fence); |
141 | ASSERT_TRUE(producer_status.ok()); | 155 | ASSERT_TRUE(producer_status.ok()); |
142 | auto producer = producer_status.take(); | 156 | auto producer = producer_status.take(); |
143 | ASSERT_NE(nullptr, producer); | 157 | ASSERT_NE(nullptr, producer); |
@@ -147,20 +161,10 @@ TEST_F(BufferHubQueueTest, TestProducerConsumer) { | |||
147 | 161 | ||
148 | // Second time the just the POSTED buffer should be dequeued. | 162 | // Second time the just the POSTED buffer should be dequeued. |
149 | uint64_t seq_out = 0; | 163 | uint64_t seq_out = 0; |
150 | consumer_status = consumer_queue_->Dequeue(0, &slot, &seq_out, &fence); | 164 | consumer_status = consumer_queue_->Dequeue(100, &slot, &seq_out, &fence); |
151 | ASSERT_TRUE(consumer_status.ok()); | 165 | ASSERT_TRUE(consumer_status.ok()); |
152 | EXPECT_TRUE(fence.IsValid()); | 166 | EXPECT_TRUE(fence.IsValid()); |
153 | 167 | ||
154 | struct stat acquire_fence_stat; | ||
155 | ASSERT_EQ(0, fstat(fence.Get(), &acquire_fence_stat)); | ||
156 | |||
157 | // The file descriptors should refer to the same file object. Testing the | ||
158 | // device id and inode is a proxy for testing that the fds refer to the same | ||
159 | // file object. | ||
160 | EXPECT_NE(post_fence.Get(), fence.Get()); | ||
161 | EXPECT_EQ(post_fence_stat.st_dev, acquire_fence_stat.st_dev); | ||
162 | EXPECT_EQ(post_fence_stat.st_ino, acquire_fence_stat.st_ino); | ||
163 | |||
164 | auto consumer = consumer_status.take(); | 168 | auto consumer = consumer_status.take(); |
165 | ASSERT_NE(nullptr, consumer); | 169 | ASSERT_NE(nullptr, consumer); |
166 | ASSERT_EQ(seq_in, seq_out); | 170 | ASSERT_EQ(seq_in, seq_out); |
@@ -196,12 +200,11 @@ TEST_F(BufferHubQueueTest, TestRemoveBuffer) { | |||
196 | 200 | ||
197 | for (size_t i = 0; i < kBufferCount; i++) { | 201 | for (size_t i = 0; i < kBufferCount; i++) { |
198 | Entry* entry = &buffers[i]; | 202 | Entry* entry = &buffers[i]; |
199 | auto producer_status = | 203 | auto producer_status = producer_queue_->Dequeue( |
200 | producer_queue_->Dequeue(0, &entry->slot, &entry->fence); | 204 | /*timeout_ms=*/100, &entry->slot, &entry->fence); |
201 | ASSERT_TRUE(producer_status.ok()); | 205 | ASSERT_TRUE(producer_status.ok()); |
202 | entry->buffer = producer_status.take(); | 206 | entry->buffer = producer_status.take(); |
203 | ASSERT_NE(nullptr, entry->buffer); | 207 | ASSERT_NE(nullptr, entry->buffer); |
204 | EXPECT_EQ(i, entry->slot); | ||
205 | } | 208 | } |
206 | 209 | ||
207 | // Remove a buffer and make sure both queues reflect the change. | 210 | // Remove a buffer and make sure both queues reflect the change. |
@@ -218,8 +221,8 @@ TEST_F(BufferHubQueueTest, TestRemoveBuffer) { | |||
218 | buffers[0].buffer = nullptr; | 221 | buffers[0].buffer = nullptr; |
219 | 222 | ||
220 | // Now the consumer queue should know it's gone. | 223 | // Now the consumer queue should know it's gone. |
221 | EXPECT_FALSE(consumer_queue_->HandleQueueEvents()); | 224 | EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100)); |
222 | EXPECT_EQ(kBufferCount - 1, consumer_queue_->capacity()); | 225 | ASSERT_EQ(kBufferCount - 1, consumer_queue_->capacity()); |
223 | 226 | ||
224 | // Allocate a new buffer. This should take the first empty slot. | 227 | // Allocate a new buffer. This should take the first empty slot. |
225 | size_t slot; | 228 | size_t slot; |
@@ -286,17 +289,20 @@ TEST_F(BufferHubQueueTest, TestMultipleConsumers) { | |||
286 | auto silent_queue = producer_queue_->CreateSilentConsumerQueue(); | 289 | auto silent_queue = producer_queue_->CreateSilentConsumerQueue(); |
287 | ASSERT_NE(nullptr, silent_queue); | 290 | ASSERT_NE(nullptr, silent_queue); |
288 | 291 | ||
289 | // Check that buffers are correctly imported on construction. | 292 | // Check that silent queue doesn't import buffers on creation. |
290 | EXPECT_EQ(kBufferCount, silent_queue->capacity()); | 293 | EXPECT_EQ(0, silent_queue->capacity()); |
291 | 294 | ||
292 | // Dequeue and post a buffer. | 295 | // Dequeue and post a buffer. |
293 | size_t slot; | 296 | size_t slot; |
294 | LocalHandle fence; | 297 | LocalHandle fence; |
295 | auto producer_status = producer_queue_->Dequeue(0, &slot, &fence); | 298 | auto producer_status = |
299 | producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence); | ||
296 | ASSERT_TRUE(producer_status.ok()); | 300 | ASSERT_TRUE(producer_status.ok()); |
297 | auto producer_buffer = producer_status.take(); | 301 | auto producer_buffer = producer_status.take(); |
298 | ASSERT_NE(nullptr, producer_buffer); | 302 | ASSERT_NE(nullptr, producer_buffer); |
299 | ASSERT_EQ(0, producer_buffer->Post<void>({})); | 303 | ASSERT_EQ(0, producer_buffer->Post<void>({})); |
304 | // After post, check the number of remaining available buffers. | ||
305 | EXPECT_EQ(kBufferCount - 1, producer_queue_->count()); | ||
300 | 306 | ||
301 | // Currently we expect no buffer to be available prior to calling | 307 | // Currently we expect no buffer to be available prior to calling |
302 | // WaitForBuffers/HandleQueueEvents. | 308 | // WaitForBuffers/HandleQueueEvents. |
@@ -314,23 +320,30 @@ TEST_F(BufferHubQueueTest, TestMultipleConsumers) { | |||
314 | EXPECT_EQ(1u, consumer_queue_->count()); | 320 | EXPECT_EQ(1u, consumer_queue_->count()); |
315 | 321 | ||
316 | // Reclaim released/ignored buffers. | 322 | // Reclaim released/ignored buffers. |
317 | producer_queue_->HandleQueueEvents(); | 323 | ASSERT_EQ(kBufferCount - 1, producer_queue_->count()); |
324 | |||
325 | usleep(10000); | ||
326 | WaitAndHandleOnce(producer_queue_.get(), /*timeout_ms=*/100); | ||
318 | ASSERT_EQ(kBufferCount - 1, producer_queue_->count()); | 327 | ASSERT_EQ(kBufferCount - 1, producer_queue_->count()); |
319 | 328 | ||
320 | // Post another buffer. | 329 | // Post another buffer. |
321 | producer_status = producer_queue_->Dequeue(0, &slot, &fence); | 330 | producer_status = producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence); |
322 | ASSERT_TRUE(producer_status.ok()); | 331 | ASSERT_TRUE(producer_status.ok()); |
323 | producer_buffer = producer_status.take(); | 332 | producer_buffer = producer_status.take(); |
324 | ASSERT_NE(nullptr, producer_buffer); | 333 | ASSERT_NE(nullptr, producer_buffer); |
325 | ASSERT_EQ(0, producer_buffer->Post<void>({})); | 334 | ASSERT_EQ(0, producer_buffer->Post<void>({})); |
326 | 335 | ||
327 | // Verify that the consumer queue receives it. | 336 | // Verify that the consumer queue receives it. |
328 | EXPECT_EQ(1u, consumer_queue_->count()); | 337 | size_t consumer_queue_count = consumer_queue_->count(); |
329 | EXPECT_TRUE(consumer_queue_->HandleQueueEvents()); | 338 | WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100); |
330 | EXPECT_EQ(2u, consumer_queue_->count()); | 339 | EXPECT_LT(consumer_queue_count, consumer_queue_->count()); |
340 | |||
341 | // Save the current consumer queue buffer count to compare after the dequeue. | ||
342 | consumer_queue_count = consumer_queue_->count(); | ||
331 | 343 | ||
332 | // Dequeue and acquire/release (discard) buffers on the consumer end. | 344 | // Dequeue and acquire/release (discard) buffers on the consumer end. |
333 | auto consumer_status = consumer_queue_->Dequeue(0, &slot, &fence); | 345 | auto consumer_status = |
346 | consumer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence); | ||
334 | ASSERT_TRUE(consumer_status.ok()); | 347 | ASSERT_TRUE(consumer_status.ok()); |
335 | auto consumer_buffer = consumer_status.take(); | 348 | auto consumer_buffer = consumer_status.take(); |
336 | ASSERT_NE(nullptr, consumer_buffer); | 349 | ASSERT_NE(nullptr, consumer_buffer); |
@@ -338,7 +351,7 @@ TEST_F(BufferHubQueueTest, TestMultipleConsumers) { | |||
338 | 351 | ||
339 | // Buffer should be returned to the producer queue without being handled by | 352 | // Buffer should be returned to the producer queue without being handled by |
340 | // the silent consumer queue. | 353 | // the silent consumer queue. |
341 | EXPECT_EQ(1u, consumer_queue_->count()); | 354 | EXPECT_GT(consumer_queue_count, consumer_queue_->count()); |
342 | EXPECT_EQ(kBufferCount - 2, producer_queue_->count()); | 355 | EXPECT_EQ(kBufferCount - 2, producer_queue_->count()); |
343 | EXPECT_TRUE(producer_queue_->HandleQueueEvents()); | 356 | EXPECT_TRUE(producer_queue_->HandleQueueEvents()); |
344 | EXPECT_EQ(kBufferCount - 1, producer_queue_->count()); | 357 | EXPECT_EQ(kBufferCount - 1, producer_queue_->count()); |
@@ -362,13 +375,13 @@ TEST_F(BufferHubQueueTest, TestMetadata) { | |||
362 | for (auto mi : ms) { | 375 | for (auto mi : ms) { |
363 | size_t slot; | 376 | size_t slot; |
364 | LocalHandle fence; | 377 | LocalHandle fence; |
365 | auto p1_status = producer_queue_->Dequeue(0, &slot, &fence); | 378 | auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); |
366 | ASSERT_TRUE(p1_status.ok()); | 379 | ASSERT_TRUE(p1_status.ok()); |
367 | auto p1 = p1_status.take(); | 380 | auto p1 = p1_status.take(); |
368 | ASSERT_NE(nullptr, p1); | 381 | ASSERT_NE(nullptr, p1); |
369 | ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0); | 382 | ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0); |
370 | TestMetadata mo; | 383 | TestMetadata mo; |
371 | auto c1_status = consumer_queue_->Dequeue(0, &slot, &mo, &fence); | 384 | auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence); |
372 | ASSERT_TRUE(c1_status.ok()); | 385 | ASSERT_TRUE(c1_status.ok()); |
373 | auto c1 = c1_status.take(); | 386 | auto c1 = c1_status.take(); |
374 | ASSERT_EQ(mi.a, mo.a); | 387 | ASSERT_EQ(mi.a, mo.a); |
@@ -387,7 +400,7 @@ TEST_F(BufferHubQueueTest, TestMetadataMismatch) { | |||
387 | int64_t mi = 3; | 400 | int64_t mi = 3; |
388 | size_t slot; | 401 | size_t slot; |
389 | LocalHandle fence; | 402 | LocalHandle fence; |
390 | auto p1_status = producer_queue_->Dequeue(0, &slot, &fence); | 403 | auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); |
391 | ASSERT_TRUE(p1_status.ok()); | 404 | ASSERT_TRUE(p1_status.ok()); |
392 | auto p1 = p1_status.take(); | 405 | auto p1 = p1_status.take(); |
393 | ASSERT_NE(nullptr, p1); | 406 | ASSERT_NE(nullptr, p1); |
@@ -395,7 +408,7 @@ TEST_F(BufferHubQueueTest, TestMetadataMismatch) { | |||
395 | 408 | ||
396 | int32_t mo; | 409 | int32_t mo; |
397 | // Acquire a buffer with mismatched metadata is not OK. | 410 | // Acquire a buffer with mismatched metadata is not OK. |
398 | auto c1_status = consumer_queue_->Dequeue(0, &slot, &mo, &fence); | 411 | auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence); |
399 | ASSERT_FALSE(c1_status.ok()); | 412 | ASSERT_FALSE(c1_status.ok()); |
400 | } | 413 | } |
401 | 414 | ||
@@ -406,14 +419,14 @@ TEST_F(BufferHubQueueTest, TestEnqueue) { | |||
406 | 419 | ||
407 | size_t slot; | 420 | size_t slot; |
408 | LocalHandle fence; | 421 | LocalHandle fence; |
409 | auto p1_status = producer_queue_->Dequeue(0, &slot, &fence); | 422 | auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); |
410 | ASSERT_TRUE(p1_status.ok()); | 423 | ASSERT_TRUE(p1_status.ok()); |
411 | auto p1 = p1_status.take(); | 424 | auto p1 = p1_status.take(); |
412 | ASSERT_NE(nullptr, p1); | 425 | ASSERT_NE(nullptr, p1); |
413 | 426 | ||
414 | int64_t mo; | 427 | int64_t mo; |
415 | producer_queue_->Enqueue(p1, slot); | 428 | producer_queue_->Enqueue(p1, slot, 0ULL); |
416 | auto c1_status = consumer_queue_->Dequeue(0, &slot, &mo, &fence); | 429 | auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence); |
417 | ASSERT_FALSE(c1_status.ok()); | 430 | ASSERT_FALSE(c1_status.ok()); |
418 | } | 431 | } |
419 | 432 | ||
@@ -424,14 +437,14 @@ TEST_F(BufferHubQueueTest, TestAllocateBuffer) { | |||
424 | size_t s1; | 437 | size_t s1; |
425 | AllocateBuffer(); | 438 | AllocateBuffer(); |
426 | LocalHandle fence; | 439 | LocalHandle fence; |
427 | auto p1_status = producer_queue_->Dequeue(0, &s1, &fence); | 440 | auto p1_status = producer_queue_->Dequeue(100, &s1, &fence); |
428 | ASSERT_TRUE(p1_status.ok()); | 441 | ASSERT_TRUE(p1_status.ok()); |
429 | auto p1 = p1_status.take(); | 442 | auto p1 = p1_status.take(); |
430 | ASSERT_NE(nullptr, p1); | 443 | ASSERT_NE(nullptr, p1); |
431 | 444 | ||
432 | // producer queue is exhausted | 445 | // producer queue is exhausted |
433 | size_t s2; | 446 | size_t s2; |
434 | auto p2_status = producer_queue_->Dequeue(0, &s2, &fence); | 447 | auto p2_status = producer_queue_->Dequeue(100, &s2, &fence); |
435 | ASSERT_FALSE(p2_status.ok()); | 448 | ASSERT_FALSE(p2_status.ok()); |
436 | ASSERT_EQ(ETIMEDOUT, p2_status.error()); | 449 | ASSERT_EQ(ETIMEDOUT, p2_status.error()); |
437 | 450 | ||
@@ -441,7 +454,7 @@ TEST_F(BufferHubQueueTest, TestAllocateBuffer) { | |||
441 | ASSERT_EQ(producer_queue_->capacity(), 2U); | 454 | ASSERT_EQ(producer_queue_->capacity(), 2U); |
442 | 455 | ||
443 | // now we can dequeue again | 456 | // now we can dequeue again |
444 | p2_status = producer_queue_->Dequeue(0, &s2, &fence); | 457 | p2_status = producer_queue_->Dequeue(100, &s2, &fence); |
445 | ASSERT_TRUE(p2_status.ok()); | 458 | ASSERT_TRUE(p2_status.ok()); |
446 | auto p2 = p2_status.take(); | 459 | auto p2 = p2_status.take(); |
447 | ASSERT_NE(nullptr, p2); | 460 | ASSERT_NE(nullptr, p2); |
@@ -456,7 +469,7 @@ TEST_F(BufferHubQueueTest, TestAllocateBuffer) { | |||
456 | int64_t seq = 1; | 469 | int64_t seq = 1; |
457 | ASSERT_EQ(p1->Post(LocalHandle(), seq), 0); | 470 | ASSERT_EQ(p1->Post(LocalHandle(), seq), 0); |
458 | size_t cs1, cs2; | 471 | size_t cs1, cs2; |
459 | auto c1_status = consumer_queue_->Dequeue(0, &cs1, &seq, &fence); | 472 | auto c1_status = consumer_queue_->Dequeue(100, &cs1, &seq, &fence); |
460 | ASSERT_TRUE(c1_status.ok()); | 473 | ASSERT_TRUE(c1_status.ok()); |
461 | auto c1 = c1_status.take(); | 474 | auto c1 = c1_status.take(); |
462 | ASSERT_NE(nullptr, c1); | 475 | ASSERT_NE(nullptr, c1); |
@@ -465,7 +478,7 @@ TEST_F(BufferHubQueueTest, TestAllocateBuffer) { | |||
465 | ASSERT_EQ(cs1, s1); | 478 | ASSERT_EQ(cs1, s1); |
466 | 479 | ||
467 | ASSERT_EQ(p2->Post(LocalHandle(), seq), 0); | 480 | ASSERT_EQ(p2->Post(LocalHandle(), seq), 0); |
468 | auto c2_status = consumer_queue_->Dequeue(0, &cs2, &seq, &fence); | 481 | auto c2_status = consumer_queue_->Dequeue(100, &cs2, &seq, &fence); |
469 | ASSERT_TRUE(c2_status.ok()); | 482 | ASSERT_TRUE(c2_status.ok()); |
470 | auto c2 = c2_status.take(); | 483 | auto c2 = c2_status.take(); |
471 | ASSERT_NE(nullptr, c2); | 484 | ASSERT_NE(nullptr, c2); |
@@ -485,7 +498,7 @@ TEST_F(BufferHubQueueTest, TestUsageSetMask) { | |||
485 | 498 | ||
486 | LocalHandle fence; | 499 | LocalHandle fence; |
487 | size_t slot; | 500 | size_t slot; |
488 | auto p1_status = producer_queue_->Dequeue(0, &slot, &fence); | 501 | auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); |
489 | ASSERT_TRUE(p1_status.ok()); | 502 | ASSERT_TRUE(p1_status.ok()); |
490 | auto p1 = p1_status.take(); | 503 | auto p1 = p1_status.take(); |
491 | ASSERT_EQ(p1->usage() & set_mask, set_mask); | 504 | ASSERT_EQ(p1->usage() & set_mask, set_mask); |
@@ -504,7 +517,7 @@ TEST_F(BufferHubQueueTest, TestUsageClearMask) { | |||
504 | 517 | ||
505 | LocalHandle fence; | 518 | LocalHandle fence; |
506 | size_t slot; | 519 | size_t slot; |
507 | auto p1_status = producer_queue_->Dequeue(0, &slot, &fence); | 520 | auto p1_status = producer_queue_->Dequeue(100, &slot, &fence); |
508 | ASSERT_TRUE(p1_status.ok()); | 521 | ASSERT_TRUE(p1_status.ok()); |
509 | auto p1 = p1_status.take(); | 522 | auto p1 = p1_status.take(); |
510 | ASSERT_EQ(0u, p1->usage() & clear_mask); | 523 | ASSERT_EQ(0u, p1->usage() & clear_mask); |
@@ -543,9 +556,9 @@ TEST_F(BufferHubQueueTest, TestUsageDenyClearMask) { | |||
543 | ASSERT_TRUE(status.ok()); | 556 | ASSERT_TRUE(status.ok()); |
544 | 557 | ||
545 | // While allocation without those bits should fail. | 558 | // While allocation without those bits should fail. |
546 | status = producer_queue_->AllocateBuffer( | 559 | status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight, |
547 | kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat, | 560 | kBufferLayerCount, kBufferFormat, |
548 | kBufferUsage & ~deny_clear_mask); | 561 | kBufferUsage & ~deny_clear_mask); |
549 | ASSERT_FALSE(status.ok()); | 562 | ASSERT_FALSE(status.ok()); |
550 | ASSERT_EQ(EINVAL, status.error()); | 563 | ASSERT_EQ(EINVAL, status.error()); |
551 | } | 564 | } |
@@ -603,7 +616,7 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { | |||
603 | 616 | ||
604 | // Free all buffers when one buffer is dequeued. | 617 | // Free all buffers when one buffer is dequeued. |
605 | CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); | 618 | CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); |
606 | producer_status = producer_queue_->Dequeue(0, &slot, &fence); | 619 | producer_status = producer_queue_->Dequeue(100, &slot, &fence); |
607 | ASSERT_TRUE(producer_status.ok()); | 620 | ASSERT_TRUE(producer_status.ok()); |
608 | status = producer_queue_->FreeAllBuffers(); | 621 | status = producer_queue_->FreeAllBuffers(); |
609 | EXPECT_TRUE(status.ok()); | 622 | EXPECT_TRUE(status.ok()); |
@@ -611,7 +624,7 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { | |||
611 | // Free all buffers when all buffers are dequeued. | 624 | // Free all buffers when all buffers are dequeued. |
612 | CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); | 625 | CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); |
613 | for (size_t i = 0; i < kBufferCount; i++) { | 626 | for (size_t i = 0; i < kBufferCount; i++) { |
614 | producer_status = producer_queue_->Dequeue(0, &slot, &fence); | 627 | producer_status = producer_queue_->Dequeue(100, &slot, &fence); |
615 | ASSERT_TRUE(producer_status.ok()); | 628 | ASSERT_TRUE(producer_status.ok()); |
616 | } | 629 | } |
617 | status = producer_queue_->FreeAllBuffers(); | 630 | status = producer_queue_->FreeAllBuffers(); |
@@ -619,7 +632,7 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { | |||
619 | 632 | ||
620 | // Free all buffers when one buffer is posted. | 633 | // Free all buffers when one buffer is posted. |
621 | CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); | 634 | CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); |
622 | producer_status = producer_queue_->Dequeue(0, &slot, &fence); | 635 | producer_status = producer_queue_->Dequeue(100, &slot, &fence); |
623 | ASSERT_TRUE(producer_status.ok()); | 636 | ASSERT_TRUE(producer_status.ok()); |
624 | producer_buffer = producer_status.take(); | 637 | producer_buffer = producer_status.take(); |
625 | ASSERT_NE(nullptr, producer_buffer); | 638 | ASSERT_NE(nullptr, producer_buffer); |
@@ -630,7 +643,7 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { | |||
630 | // Free all buffers when all buffers are posted. | 643 | // Free all buffers when all buffers are posted. |
631 | CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); | 644 | CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); |
632 | for (size_t i = 0; i < kBufferCount; i++) { | 645 | for (size_t i = 0; i < kBufferCount; i++) { |
633 | producer_status = producer_queue_->Dequeue(0, &slot, &fence); | 646 | producer_status = producer_queue_->Dequeue(100, &slot, &fence); |
634 | ASSERT_TRUE(producer_status.ok()); | 647 | ASSERT_TRUE(producer_status.ok()); |
635 | producer_buffer = producer_status.take(); | 648 | producer_buffer = producer_status.take(); |
636 | ASSERT_NE(nullptr, producer_buffer); | 649 | ASSERT_NE(nullptr, producer_buffer); |
@@ -642,12 +655,12 @@ TEST_F(BufferHubQueueTest, TestFreeAllBuffers) { | |||
642 | // Free all buffers when all buffers are acquired. | 655 | // Free all buffers when all buffers are acquired. |
643 | CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); | 656 | CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount); |
644 | for (size_t i = 0; i < kBufferCount; i++) { | 657 | for (size_t i = 0; i < kBufferCount; i++) { |
645 | producer_status = producer_queue_->Dequeue(0, &slot, &fence); | 658 | producer_status = producer_queue_->Dequeue(100, &slot, &fence); |
646 | ASSERT_TRUE(producer_status.ok()); | 659 | ASSERT_TRUE(producer_status.ok()); |
647 | producer_buffer = producer_status.take(); | 660 | producer_buffer = producer_status.take(); |
648 | ASSERT_NE(nullptr, producer_buffer); | 661 | ASSERT_NE(nullptr, producer_buffer); |
649 | ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); | 662 | ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq))); |
650 | consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence); | 663 | consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence); |
651 | ASSERT_TRUE(consumer_status.ok()); | 664 | ASSERT_TRUE(consumer_status.ok()); |
652 | } | 665 | } |
653 | 666 | ||
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp index 035252d0b..09a49dd71 100644 --- a/libs/vr/libdvr/dvr_buffer_queue.cpp +++ b/libs/vr/libdvr/dvr_buffer_queue.cpp | |||
@@ -27,15 +27,6 @@ DvrWriteBufferQueue::DvrWriteBufferQueue( | |||
27 | format_(producer_queue->default_format()) {} | 27 | format_(producer_queue->default_format()) {} |
28 | 28 | ||
29 | int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) { | 29 | int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) { |
30 | if (producer_queue_->metadata_size() != sizeof(DvrNativeBufferMetadata)) { | ||
31 | ALOGE( | ||
32 | "DvrWriteBufferQueue::GetNativeWindow: The size of buffer metadata " | ||
33 | "(%zu) of the write queue does not match of size of " | ||
34 | "DvrNativeBufferMetadata (%zu).", | ||
35 | producer_queue_->metadata_size(), sizeof(DvrNativeBufferMetadata)); | ||
36 | return -EINVAL; | ||
37 | } | ||
38 | |||
39 | if (native_window_ == nullptr) { | 30 | if (native_window_ == nullptr) { |
40 | // Lazy creation of |native_window|, as not everyone is using | 31 | // Lazy creation of |native_window|, as not everyone is using |
41 | // DvrWriteBufferQueue as an external surface. | 32 | // DvrWriteBufferQueue as an external surface. |
@@ -63,10 +54,27 @@ int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) { | |||
63 | } | 54 | } |
64 | 55 | ||
65 | int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer, | 56 | int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer, |
66 | int* out_fence_fd, size_t* out_slot) { | 57 | int* out_fence_fd) { |
58 | DvrNativeBufferMetadata meta; | ||
59 | DvrWriteBuffer* buffer = nullptr; | ||
60 | int fence_fd = -1; | ||
61 | if (const int ret = GainBuffer(timeout, &buffer, &meta, &fence_fd)) | ||
62 | return ret; | ||
63 | if (!buffer) | ||
64 | return -ENOMEM; | ||
65 | |||
66 | write_buffers_[buffer->slot].reset(buffer); | ||
67 | write_buffer->write_buffer = std::move(buffer->write_buffer); | ||
68 | *out_fence_fd = fence_fd; | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | int DvrWriteBufferQueue::GainBuffer(int timeout, | ||
73 | DvrWriteBuffer** out_write_buffer, | ||
74 | DvrNativeBufferMetadata* out_meta, | ||
75 | int* out_fence_fd) { | ||
67 | size_t slot; | 76 | size_t slot; |
68 | pdx::LocalHandle fence; | 77 | pdx::LocalHandle release_fence; |
69 | std::shared_ptr<BufferProducer> buffer_producer; | ||
70 | 78 | ||
71 | // Need to retry N+1 times, where N is total number of buffers in the queue. | 79 | // Need to retry N+1 times, where N is total number of buffers in the queue. |
72 | // As in the worst case, we will dequeue all N buffers and reallocate them, on | 80 | // As in the worst case, we will dequeue all N buffers and reallocate them, on |
@@ -75,15 +83,29 @@ int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer, | |||
75 | size_t retry = 0; | 83 | size_t retry = 0; |
76 | 84 | ||
77 | for (; retry < max_retries; retry++) { | 85 | for (; retry < max_retries; retry++) { |
78 | auto buffer_status = producer_queue_->Dequeue(timeout, &slot, &fence); | 86 | auto buffer_status = |
87 | producer_queue_->Dequeue(timeout, &slot, out_meta, &release_fence); | ||
79 | if (!buffer_status) { | 88 | if (!buffer_status) { |
80 | ALOGE_IF(buffer_status.error() != ETIMEDOUT, | 89 | ALOGE_IF(buffer_status.error() != ETIMEDOUT, |
81 | "DvrWriteBufferQueue::Dequeue: Failed to dequeue buffer: %s", | 90 | "DvrWriteBufferQueue::GainBuffer: Failed to dequeue buffer: %s", |
82 | buffer_status.GetErrorMessage().c_str()); | 91 | buffer_status.GetErrorMessage().c_str()); |
83 | return -buffer_status.error(); | 92 | return -buffer_status.error(); |
84 | } | 93 | } |
85 | 94 | ||
86 | buffer_producer = buffer_status.take(); | 95 | if (write_buffers_[slot] == nullptr) { |
96 | // Lazy initialization of a write_buffers_ slot. Note that a slot will | ||
97 | // only be dynamically allocated once during the entire cycle life of a | ||
98 | // queue. | ||
99 | write_buffers_[slot] = std::make_unique<DvrWriteBuffer>(); | ||
100 | write_buffers_[slot]->slot = slot; | ||
101 | } | ||
102 | |||
103 | LOG_ALWAYS_FATAL_IF( | ||
104 | write_buffers_[slot]->write_buffer, | ||
105 | "DvrWriteBufferQueue::GainBuffer: Buffer slot is not empty: %zu", slot); | ||
106 | write_buffers_[slot]->write_buffer = std::move(buffer_status.take()); | ||
107 | |||
108 | const auto& buffer_producer = write_buffers_[slot]->write_buffer; | ||
87 | if (!buffer_producer) | 109 | if (!buffer_producer) |
88 | return -ENOMEM; | 110 | return -ENOMEM; |
89 | 111 | ||
@@ -122,6 +144,9 @@ int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer, | |||
122 | remove_status.GetErrorMessage().c_str()); | 144 | remove_status.GetErrorMessage().c_str()); |
123 | return -remove_status.error(); | 145 | return -remove_status.error(); |
124 | } | 146 | } |
147 | // Make sure that the previously allocated buffer is dereferenced from | ||
148 | // write_buffers_ array. | ||
149 | write_buffers_[slot]->write_buffer = nullptr; | ||
125 | 150 | ||
126 | auto allocate_status = producer_queue_->AllocateBuffer( | 151 | auto allocate_status = producer_queue_->AllocateBuffer( |
127 | width_, height_, old_layer_count, format_, old_usage); | 152 | width_, height_, old_layer_count, format_, old_usage); |
@@ -139,46 +164,8 @@ int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer, | |||
139 | return -ENOMEM; | 164 | return -ENOMEM; |
140 | } | 165 | } |
141 | 166 | ||
142 | write_buffer->write_buffer = std::move(buffer_producer); | ||
143 | *out_fence_fd = fence.Release(); | ||
144 | if (out_slot) { | ||
145 | // TODO(b/65469368): Remove this null check once dvrWriteBufferQueueDequeue | ||
146 | // is deprecated. | ||
147 | *out_slot = slot; | ||
148 | } | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | int DvrWriteBufferQueue::GainBuffer(int timeout, | ||
153 | DvrWriteBuffer** out_write_buffer, | ||
154 | DvrNativeBufferMetadata* out_meta, | ||
155 | int* out_fence_fd) { | ||
156 | DvrWriteBuffer write_buffer; | ||
157 | int fence_fd; | ||
158 | size_t slot; | ||
159 | const int ret = Dequeue(timeout, &write_buffer, &fence_fd, &slot); | ||
160 | if (ret < 0) { | ||
161 | ALOGE_IF( | ||
162 | ret != -ETIMEDOUT, | ||
163 | "DvrWriteBufferQueue::GainBuffer: Failed to dequeue buffer, ret=%d", | ||
164 | ret); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | if (write_buffers_[slot] == nullptr) { | ||
169 | // Lazy initialization of a write_buffers_ slot. Note that a slot will only | ||
170 | // be dynamically allocated once during the entire cycle life of a queue. | ||
171 | write_buffers_[slot] = std::make_unique<DvrWriteBuffer>(); | ||
172 | write_buffers_[slot]->slot = slot; | ||
173 | } | ||
174 | |||
175 | LOG_ALWAYS_FATAL_IF( | ||
176 | write_buffers_[slot]->write_buffer, | ||
177 | "DvrWriteBufferQueue::GainBuffer: Buffer slot is not empty: %zu", slot); | ||
178 | write_buffers_[slot]->write_buffer = std::move(write_buffer.write_buffer); | ||
179 | |||
180 | *out_write_buffer = write_buffers_[slot].release(); | 167 | *out_write_buffer = write_buffers_[slot].release(); |
181 | *out_fence_fd = fence_fd; | 168 | *out_fence_fd = release_fence.Release(); |
182 | 169 | ||
183 | return 0; | 170 | return 0; |
184 | } | 171 | } |
@@ -202,14 +189,16 @@ int DvrWriteBufferQueue::PostBuffer(DvrWriteBuffer* write_buffer, | |||
202 | } | 189 | } |
203 | if (write_buffer->write_buffer->id() != producer_queue_->GetBufferId(slot)) { | 190 | if (write_buffer->write_buffer->id() != producer_queue_->GetBufferId(slot)) { |
204 | ALOGE( | 191 | ALOGE( |
205 | "DvrWriteBufferQueue::PostBuffer: Buffer to be released does not " | 192 | "DvrWriteBufferQueue::PostBuffer: Buffer to be posted does not " |
206 | "belong to this buffer queue."); | 193 | "belong to this buffer queue. Posting buffer: id=%d, buffer in " |
194 | "queue: id=%d", | ||
195 | write_buffer->write_buffer->id(), producer_queue_->GetBufferId(slot)); | ||
207 | return -EINVAL; | 196 | return -EINVAL; |
208 | } | 197 | } |
209 | 198 | ||
199 | write_buffer->write_buffer->SetQueueIndex(next_post_index_++); | ||
210 | pdx::LocalHandle fence(ready_fence_fd); | 200 | pdx::LocalHandle fence(ready_fence_fd); |
211 | // TODO(b/65455724): All BufferHub operations should be async. | 201 | const int ret = write_buffer->write_buffer->PostAsync(meta, fence); |
212 | const int ret = write_buffer->write_buffer->Post(fence, meta, sizeof(*meta)); | ||
213 | if (ret < 0) { | 202 | if (ret < 0) { |
214 | ALOGE("DvrWriteBufferQueue::PostBuffer: Failed to post buffer, ret=%d", | 203 | ALOGE("DvrWriteBufferQueue::PostBuffer: Failed to post buffer, ret=%d", |
215 | ret); | 204 | ret); |
@@ -316,8 +305,7 @@ int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout, | |||
316 | if (!write_queue || !write_buffer || !out_fence_fd) | 305 | if (!write_queue || !write_buffer || !out_fence_fd) |
317 | return -EINVAL; | 306 | return -EINVAL; |
318 | 307 | ||
319 | // TODO(b/65469368): Deprecate this API once new GainBuffer API is in use. | 308 | return write_queue->Dequeue(timeout, write_buffer, out_fence_fd); |
320 | return write_queue->Dequeue(timeout, write_buffer, out_fence_fd, nullptr); | ||
321 | } | 309 | } |
322 | 310 | ||
323 | int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout, | 311 | int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout, |
@@ -370,8 +358,8 @@ int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) { | |||
370 | } | 358 | } |
371 | 359 | ||
372 | int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer, | 360 | int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer, |
373 | int* out_fence_fd, size_t* out_slot, | 361 | int* out_fence_fd, void* out_meta, |
374 | void* out_meta, size_t meta_size_bytes) { | 362 | size_t meta_size_bytes) { |
375 | if (meta_size_bytes != consumer_queue_->metadata_size()) { | 363 | if (meta_size_bytes != consumer_queue_->metadata_size()) { |
376 | ALOGE( | 364 | ALOGE( |
377 | "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), " | 365 | "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), " |
@@ -394,11 +382,6 @@ int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer, | |||
394 | read_buffer->read_buffer = buffer_status.take(); | 382 | read_buffer->read_buffer = buffer_status.take(); |
395 | *out_fence_fd = acquire_fence.Release(); | 383 | *out_fence_fd = acquire_fence.Release(); |
396 | 384 | ||
397 | if (out_slot) { | ||
398 | // TODO(b/65469368): Remove this null check once dvrReadBufferQueueDequeue | ||
399 | // is deprecated. | ||
400 | *out_slot = slot; | ||
401 | } | ||
402 | return 0; | 385 | return 0; |
403 | } | 386 | } |
404 | 387 | ||
@@ -406,17 +389,15 @@ int DvrReadBufferQueue::AcquireBuffer(int timeout, | |||
406 | DvrReadBuffer** out_read_buffer, | 389 | DvrReadBuffer** out_read_buffer, |
407 | DvrNativeBufferMetadata* out_meta, | 390 | DvrNativeBufferMetadata* out_meta, |
408 | int* out_fence_fd) { | 391 | int* out_fence_fd) { |
409 | DvrReadBuffer read_buffer; | ||
410 | int fence_fd; | ||
411 | size_t slot; | 392 | size_t slot; |
412 | const int ret = Dequeue(timeout, &read_buffer, &fence_fd, &slot, out_meta, | 393 | pdx::LocalHandle acquire_fence; |
413 | sizeof(*out_meta)); | 394 | auto buffer_status = |
414 | if (ret < 0) { | 395 | consumer_queue_->Dequeue(timeout, &slot, out_meta, &acquire_fence); |
415 | ALOGE_IF( | 396 | if (!buffer_status) { |
416 | ret != -ETIMEDOUT, | 397 | ALOGE_IF(buffer_status.error() != ETIMEDOUT, |
417 | "DvrReadBufferQueue::AcquireBuffer: Failed to dequeue buffer, error=%d", | 398 | "DvrReadBufferQueue::AcquireBuffer: Failed to dequeue buffer: %s", |
418 | ret); | 399 | buffer_status.GetErrorMessage().c_str()); |
419 | return ret; | 400 | return -buffer_status.error(); |
420 | } | 401 | } |
421 | 402 | ||
422 | if (read_buffers_[slot] == nullptr) { | 403 | if (read_buffers_[slot] == nullptr) { |
@@ -429,10 +410,10 @@ int DvrReadBufferQueue::AcquireBuffer(int timeout, | |||
429 | LOG_FATAL_IF( | 410 | LOG_FATAL_IF( |
430 | read_buffers_[slot]->read_buffer, | 411 | read_buffers_[slot]->read_buffer, |
431 | "DvrReadBufferQueue::AcquireBuffer: Buffer slot is not empty: %zu", slot); | 412 | "DvrReadBufferQueue::AcquireBuffer: Buffer slot is not empty: %zu", slot); |
432 | read_buffers_[slot]->read_buffer = std::move(read_buffer.read_buffer); | 413 | read_buffers_[slot]->read_buffer = std::move(buffer_status.take()); |
433 | 414 | ||
434 | *out_read_buffer = read_buffers_[slot].release(); | 415 | *out_read_buffer = read_buffers_[slot].release(); |
435 | *out_fence_fd = fence_fd; | 416 | *out_fence_fd = acquire_fence.Release(); |
436 | 417 | ||
437 | return 0; | 418 | return 0; |
438 | } | 419 | } |
@@ -457,20 +438,14 @@ int DvrReadBufferQueue::ReleaseBuffer(DvrReadBuffer* read_buffer, | |||
457 | if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) { | 438 | if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) { |
458 | ALOGE( | 439 | ALOGE( |
459 | "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released does not " | 440 | "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released does not " |
460 | "belong to this buffer queue."); | 441 | "belong to this buffer queue. Releasing buffer: id=%d, buffer in " |
442 | "queue: id=%d", | ||
443 | read_buffer->read_buffer->id(), consumer_queue_->GetBufferId(slot)); | ||
461 | return -EINVAL; | 444 | return -EINVAL; |
462 | } | 445 | } |
463 | 446 | ||
464 | pdx::LocalHandle fence(release_fence_fd); | 447 | pdx::LocalHandle fence(release_fence_fd); |
465 | int ret = 0; | 448 | int ret = read_buffer->read_buffer->ReleaseAsync(meta, fence); |
466 | if (fence) { | ||
467 | ret = read_buffer->read_buffer->Release(fence); | ||
468 | } else { | ||
469 | // TODO(b/65458354): Send metadata back to producer once shared memory based | ||
470 | // metadata is implemented. | ||
471 | // TODO(b/65455724): All BufferHub operations should be async. | ||
472 | ret = read_buffer->read_buffer->ReleaseAsync(); | ||
473 | } | ||
474 | if (ret < 0) { | 449 | if (ret < 0) { |
475 | ALOGE("DvrReadBufferQueue::ReleaseBuffer: Failed to release buffer, ret=%d", | 450 | ALOGE("DvrReadBufferQueue::ReleaseBuffer: Failed to release buffer, ret=%d", |
476 | ret); | 451 | ret); |
@@ -559,9 +534,8 @@ int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout, | |||
559 | if (meta_size_bytes != 0 && !out_meta) | 534 | if (meta_size_bytes != 0 && !out_meta) |
560 | return -EINVAL; | 535 | return -EINVAL; |
561 | 536 | ||
562 | // TODO(b/65469368): Deprecate this API once new AcquireBuffer API is in use. | 537 | return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta, |
563 | return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, nullptr, | 538 | meta_size_bytes); |
564 | out_meta, meta_size_bytes); | ||
565 | } | 539 | } |
566 | 540 | ||
567 | int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout, | 541 | int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout, |
diff --git a/libs/vr/libdvr/dvr_buffer_queue_internal.h b/libs/vr/libdvr/dvr_buffer_queue_internal.h index f9c0bfd7c..e53a6868f 100644 --- a/libs/vr/libdvr/dvr_buffer_queue_internal.h +++ b/libs/vr/libdvr/dvr_buffer_queue_internal.h | |||
@@ -42,8 +42,7 @@ struct DvrWriteBufferQueue { | |||
42 | 42 | ||
43 | int GetNativeWindow(ANativeWindow** out_window); | 43 | int GetNativeWindow(ANativeWindow** out_window); |
44 | int CreateReadQueue(DvrReadBufferQueue** out_read_queue); | 44 | int CreateReadQueue(DvrReadBufferQueue** out_read_queue); |
45 | int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd, | 45 | int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd); |
46 | size_t* out_slot); | ||
47 | int GainBuffer(int timeout, DvrWriteBuffer** out_write_buffer, | 46 | int GainBuffer(int timeout, DvrWriteBuffer** out_write_buffer, |
48 | DvrNativeBufferMetadata* out_meta, int* out_fence_fd); | 47 | DvrNativeBufferMetadata* out_meta, int* out_fence_fd); |
49 | int PostBuffer(DvrWriteBuffer* write_buffer, | 48 | int PostBuffer(DvrWriteBuffer* write_buffer, |
@@ -55,6 +54,7 @@ struct DvrWriteBufferQueue { | |||
55 | std::array<std::unique_ptr<DvrWriteBuffer>, BufferHubQueue::kMaxQueueCapacity> | 54 | std::array<std::unique_ptr<DvrWriteBuffer>, BufferHubQueue::kMaxQueueCapacity> |
56 | write_buffers_; | 55 | write_buffers_; |
57 | 56 | ||
57 | int64_t next_post_index_ = 0; | ||
58 | uint32_t width_; | 58 | uint32_t width_; |
59 | uint32_t height_; | 59 | uint32_t height_; |
60 | uint32_t format_; | 60 | uint32_t format_; |
@@ -75,7 +75,7 @@ struct DvrReadBufferQueue { | |||
75 | 75 | ||
76 | int CreateReadQueue(DvrReadBufferQueue** out_read_queue); | 76 | int CreateReadQueue(DvrReadBufferQueue** out_read_queue); |
77 | int Dequeue(int timeout, DvrReadBuffer* read_buffer, int* out_fence_fd, | 77 | int Dequeue(int timeout, DvrReadBuffer* read_buffer, int* out_fence_fd, |
78 | size_t* out_slot, void* out_meta, size_t meta_size_bytes); | 78 | void* out_meta, size_t user_metadata_size); |
79 | int AcquireBuffer(int timeout, DvrReadBuffer** out_read_buffer, | 79 | int AcquireBuffer(int timeout, DvrReadBuffer** out_read_buffer, |
80 | DvrNativeBufferMetadata* out_meta, int* out_fence_fd); | 80 | DvrNativeBufferMetadata* out_meta, int* out_fence_fd); |
81 | int ReleaseBuffer(DvrReadBuffer* read_buffer, | 81 | int ReleaseBuffer(DvrReadBuffer* read_buffer, |
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h index 8f45ce7e4..499b7c190 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api.h +++ b/libs/vr/libdvr/include/dvr/dvr_api.h | |||
@@ -15,6 +15,12 @@ | |||
15 | extern "C" { | 15 | extern "C" { |
16 | #endif | 16 | #endif |
17 | 17 | ||
18 | #ifdef __GNUC__ | ||
19 | #define ALIGNED_DVR_STRUCT(x) __attribute__((packed, aligned(x))) | ||
20 | #else | ||
21 | #define ALIGNED_DVR_STRUCT(x) | ||
22 | #endif | ||
23 | |||
18 | typedef struct ANativeWindow ANativeWindow; | 24 | typedef struct ANativeWindow ANativeWindow; |
19 | 25 | ||
20 | typedef struct DvrPoseAsync DvrPoseAsync; | 26 | typedef struct DvrPoseAsync DvrPoseAsync; |
@@ -367,7 +373,24 @@ typedef int (*DvrPerformanceSetSchedulerPolicyPtr)( | |||
367 | // existing data members. If new fields need to be added, please take extra care | 373 | // existing data members. If new fields need to be added, please take extra care |
368 | // to make sure that new data field is padded properly the size of the struct | 374 | // to make sure that new data field is padded properly the size of the struct |
369 | // stays same. | 375 | // stays same. |
370 | struct DvrNativeBufferMetadata { | 376 | struct ALIGNED_DVR_STRUCT(8) DvrNativeBufferMetadata { |
377 | #ifdef __cplusplus | ||
378 | DvrNativeBufferMetadata() | ||
379 | : timestamp(0), | ||
380 | is_auto_timestamp(0), | ||
381 | dataspace(0), | ||
382 | crop_left(0), | ||
383 | crop_top(0), | ||
384 | crop_right(0), | ||
385 | crop_bottom(0), | ||
386 | scaling_mode(0), | ||
387 | transform(0), | ||
388 | index(0), | ||
389 | user_metadata_size(0), | ||
390 | user_metadata_ptr(0), | ||
391 | release_fence_mask(0), | ||
392 | reserved{0} {} | ||
393 | #endif | ||
371 | // Timestamp of the frame. | 394 | // Timestamp of the frame. |
372 | int64_t timestamp; | 395 | int64_t timestamp; |
373 | 396 | ||
@@ -391,10 +414,32 @@ struct DvrNativeBufferMetadata { | |||
391 | // android/native_window.h | 414 | // android/native_window.h |
392 | int32_t transform; | 415 | int32_t transform; |
393 | 416 | ||
394 | // Reserved bytes for so that the struct is forward compatible. | 417 | // The index of the frame. |
395 | int32_t reserved[16]; | 418 | int64_t index; |
419 | |||
420 | // Size of additional metadata requested by user. | ||
421 | uint64_t user_metadata_size; | ||
422 | |||
423 | // Raw memory address of the additional user defined metadata. Only valid when | ||
424 | // user_metadata_size is non-zero. | ||
425 | uint64_t user_metadata_ptr; | ||
426 | |||
427 | // Only applicable for metadata retrieved from GainAsync. This indicates which | ||
428 | // consumer has pending fence that producer should epoll on. | ||
429 | uint64_t release_fence_mask; | ||
430 | |||
431 | // Reserved bytes for so that the struct is forward compatible and padding to | ||
432 | // 104 bytes so the size is a multiple of 8. | ||
433 | int32_t reserved[8]; | ||
396 | }; | 434 | }; |
397 | 435 | ||
436 | #ifdef __cplusplus | ||
437 | // Warning: DvrNativeBufferMetadata is part of the DVR API and changing its size | ||
438 | // will cause compatiblity issues between different DVR API releases. | ||
439 | static_assert(sizeof(DvrNativeBufferMetadata) == 104, | ||
440 | "Unexpected size for DvrNativeBufferMetadata"); | ||
441 | #endif | ||
442 | |||
398 | struct DvrApi_v1 { | 443 | struct DvrApi_v1 { |
399 | // Defines an API entry for V1 (no version suffix). | 444 | // Defines an API entry for V1 (no version suffix). |
400 | #define DVR_V1_API_ENTRY(name) Dvr##name##Ptr name | 445 | #define DVR_V1_API_ENTRY(name) Dvr##name##Ptr name |
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp index a9302a756..887766a53 100644 --- a/libs/vr/libdvr/tests/Android.bp +++ b/libs/vr/libdvr/tests/Android.bp | |||
@@ -42,6 +42,7 @@ cc_test { | |||
42 | "dvr_named_buffer-test.cpp", | 42 | "dvr_named_buffer-test.cpp", |
43 | ], | 43 | ], |
44 | 44 | ||
45 | header_libs: ["libdvr_headers"], | ||
45 | static_libs: static_libraries, | 46 | static_libs: static_libraries, |
46 | shared_libs: shared_libraries, | 47 | shared_libs: shared_libraries, |
47 | cflags: [ | 48 | cflags: [ |
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp index f1c5e4891..62cd8d4e5 100644 --- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp +++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp | |||
@@ -131,7 +131,7 @@ TEST_F(DvrBufferQueueTest, GainBuffer) { | |||
131 | DvrWriteBuffer* wb = nullptr; | 131 | DvrWriteBuffer* wb = nullptr; |
132 | EXPECT_FALSE(dvrWriteBufferIsValid(wb)); | 132 | EXPECT_FALSE(dvrWriteBufferIsValid(wb)); |
133 | 133 | ||
134 | DvrNativeBufferMetadata meta = {0}; | 134 | DvrNativeBufferMetadata meta; |
135 | int fence_fd = -1; | 135 | int fence_fd = -1; |
136 | ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta, | 136 | ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta, |
137 | &fence_fd); | 137 | &fence_fd); |
@@ -150,8 +150,8 @@ TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) { | |||
150 | DvrReadBufferQueue* read_queue = nullptr; | 150 | DvrReadBufferQueue* read_queue = nullptr; |
151 | DvrReadBuffer* rb = nullptr; | 151 | DvrReadBuffer* rb = nullptr; |
152 | DvrWriteBuffer* wb = nullptr; | 152 | DvrWriteBuffer* wb = nullptr; |
153 | DvrNativeBufferMetadata meta1 = {0}; | 153 | DvrNativeBufferMetadata meta1; |
154 | DvrNativeBufferMetadata meta2 = {0}; | 154 | DvrNativeBufferMetadata meta2; |
155 | int fence_fd = -1; | 155 | int fence_fd = -1; |
156 | 156 | ||
157 | ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); | 157 | ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue); |
@@ -180,7 +180,7 @@ TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) { | |||
180 | wb = nullptr; | 180 | wb = nullptr; |
181 | 181 | ||
182 | // Acquire buffer for reading. | 182 | // Acquire buffer for reading. |
183 | ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/0, &rb, &meta2, | 183 | ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb, &meta2, |
184 | &fence_fd); | 184 | &fence_fd); |
185 | ASSERT_EQ(ret, 0); | 185 | ASSERT_EQ(ret, 0); |
186 | ASSERT_NE(rb, nullptr); | 186 | ASSERT_NE(rb, nullptr); |
@@ -245,7 +245,7 @@ TEST_F(DvrBufferQueueTest, ResizeBuffer) { | |||
245 | 245 | ||
246 | int fence_fd = -1; | 246 | int fence_fd = -1; |
247 | 247 | ||
248 | DvrNativeBufferMetadata meta = {0}; | 248 | DvrNativeBufferMetadata meta; |
249 | DvrReadBufferQueue* read_queue = nullptr; | 249 | DvrReadBufferQueue* read_queue = nullptr; |
250 | DvrWriteBuffer* wb1 = nullptr; | 250 | DvrWriteBuffer* wb1 = nullptr; |
251 | DvrWriteBuffer* wb2 = nullptr; | 251 | DvrWriteBuffer* wb2 = nullptr; |
@@ -400,7 +400,7 @@ TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) { | |||
400 | // This test runs the following operations many many times. Thus we prefer to | 400 | // This test runs the following operations many many times. Thus we prefer to |
401 | // use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output. | 401 | // use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output. |
402 | std::function<void(size_t i)> Gain = [&](size_t i) { | 402 | std::function<void(size_t i)> Gain = [&](size_t i) { |
403 | int ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, | 403 | int ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10, |
404 | &wbs[i], &metas[i], &fence_fd); | 404 | &wbs[i], &metas[i], &fence_fd); |
405 | ASSERT_EQ(ret, 0); | 405 | ASSERT_EQ(ret, 0); |
406 | ASSERT_LT(fence_fd, 0); // expect invalid fence. | 406 | ASSERT_LT(fence_fd, 0); // expect invalid fence. |
@@ -434,7 +434,7 @@ TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) { | |||
434 | }; | 434 | }; |
435 | 435 | ||
436 | std::function<void(size_t i)> Acquire = [&](size_t i) { | 436 | std::function<void(size_t i)> Acquire = [&](size_t i) { |
437 | int ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/0, | 437 | int ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, |
438 | &rbs[i], &metas[i], &fence_fd); | 438 | &rbs[i], &metas[i], &fence_fd); |
439 | ASSERT_EQ(ret, 0); | 439 | ASSERT_EQ(ret, 0); |
440 | ASSERT_LT(fence_fd, 0); // expect invalid fence. | 440 | ASSERT_LT(fence_fd, 0); // expect invalid fence. |
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp index 8fce14030..10c0b31c5 100644 --- a/libs/vr/libpdx/Android.bp +++ b/libs/vr/libpdx/Android.bp | |||
@@ -36,6 +36,7 @@ cc_test { | |||
36 | "variant_tests.cpp", | 36 | "variant_tests.cpp", |
37 | ], | 37 | ], |
38 | static_libs: [ | 38 | static_libs: [ |
39 | "libcutils", | ||
39 | "libgmock", | 40 | "libgmock", |
40 | "libpdx", | 41 | "libpdx", |
41 | "liblog", | 42 | "liblog", |
diff --git a/libs/vr/libpdx/private/pdx/client_channel.h b/libs/vr/libpdx/private/pdx/client_channel.h index dbfd626d6..10a49bb8d 100644 --- a/libs/vr/libpdx/private/pdx/client_channel.h +++ b/libs/vr/libpdx/private/pdx/client_channel.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef ANDROID_PDX_CLIENT_CHANNEL_H_ | 1 | #ifndef ANDROID_PDX_CLIENT_CHANNEL_H_ |
2 | #define ANDROID_PDX_CLIENT_CHANNEL_H_ | 2 | #define ANDROID_PDX_CLIENT_CHANNEL_H_ |
3 | 3 | ||
4 | #include <vector> | ||
5 | |||
4 | #include <pdx/channel_handle.h> | 6 | #include <pdx/channel_handle.h> |
5 | #include <pdx/file_handle.h> | 7 | #include <pdx/file_handle.h> |
6 | #include <pdx/status.h> | 8 | #include <pdx/status.h> |
@@ -20,6 +22,15 @@ class ClientChannel { | |||
20 | virtual int event_fd() const = 0; | 22 | virtual int event_fd() const = 0; |
21 | virtual Status<int> GetEventMask(int events) = 0; | 23 | virtual Status<int> GetEventMask(int events) = 0; |
22 | 24 | ||
25 | struct EventSource { | ||
26 | int event_fd; | ||
27 | int event_mask; | ||
28 | }; | ||
29 | |||
30 | // Returns a set of event-generating fds with and event mask for each. These | ||
31 | // fds are owned by the ClientChannel and must never be closed by the caller. | ||
32 | virtual std::vector<EventSource> GetEventSources() const = 0; | ||
33 | |||
23 | virtual LocalChannelHandle& GetChannelHandle() = 0; | 34 | virtual LocalChannelHandle& GetChannelHandle() = 0; |
24 | virtual void* AllocateTransactionState() = 0; | 35 | virtual void* AllocateTransactionState() = 0; |
25 | virtual void FreeTransactionState(void* state) = 0; | 36 | virtual void FreeTransactionState(void* state) = 0; |
diff --git a/libs/vr/libpdx/private/pdx/mock_client_channel.h b/libs/vr/libpdx/private/pdx/mock_client_channel.h index 561c939da..49e0682bc 100644 --- a/libs/vr/libpdx/private/pdx/mock_client_channel.h +++ b/libs/vr/libpdx/private/pdx/mock_client_channel.h | |||
@@ -11,6 +11,7 @@ class MockClientChannel : public ClientChannel { | |||
11 | public: | 11 | public: |
12 | MOCK_CONST_METHOD0(GetIpcTag, uint32_t()); | 12 | MOCK_CONST_METHOD0(GetIpcTag, uint32_t()); |
13 | MOCK_CONST_METHOD0(event_fd, int()); | 13 | MOCK_CONST_METHOD0(event_fd, int()); |
14 | MOCK_CONST_METHOD0(GetEventSources, std::vector<EventSource>()); | ||
14 | MOCK_METHOD1(GetEventMask, Status<int>(int)); | 15 | MOCK_METHOD1(GetEventMask, Status<int>(int)); |
15 | MOCK_METHOD0(GetChannelHandle, LocalChannelHandle&()); | 16 | MOCK_METHOD0(GetChannelHandle, LocalChannelHandle&()); |
16 | MOCK_METHOD0(AllocateTransactionState, void*()); | 17 | MOCK_METHOD0(AllocateTransactionState, void*()); |
diff --git a/libs/vr/libpdx/private/pdx/trace.h b/libs/vr/libpdx/private/pdx/trace.h index ebe8491eb..c687fd625 100644 --- a/libs/vr/libpdx/private/pdx/trace.h +++ b/libs/vr/libpdx/private/pdx/trace.h | |||
@@ -1,35 +1,82 @@ | |||
1 | #ifndef ANDROID_PDX_TRACE_H_ | 1 | #ifndef ANDROID_PDX_TRACE_H_ |
2 | #define ANDROID_PDX_TRACE_H_ | 2 | #define ANDROID_PDX_TRACE_H_ |
3 | 3 | ||
4 | // Tracing utilities for libpdx. Tracing in the service framework is enabled | 4 | #include <array> |
5 | // under these conditions: | ||
6 | // 1. ATRACE_TAG is defined, AND | ||
7 | // 2. ATRACE_TAG does not equal ATRACE_TAG_NEVER, AND | ||
8 | // 3. PDX_TRACE_ENABLED is defined, AND | ||
9 | // 4. PDX_TRACE_ENABLED is equal to logical true. | ||
10 | // | ||
11 | // If any of these conditions are not met tracing is completely removed from the | ||
12 | // library and headers. | ||
13 | |||
14 | // If ATRACE_TAG is not defined, default to never. | ||
15 | #ifndef ATRACE_TAG | ||
16 | #define ATRACE_TAG ATRACE_TAG_NEVER | ||
17 | #endif | ||
18 | 5 | ||
19 | // Include tracing functions after the trace tag is defined. | ||
20 | #include <utils/Trace.h> | 6 | #include <utils/Trace.h> |
21 | 7 | ||
22 | // If PDX_TRACE_ENABLED is not defined, default to off. | 8 | // Enables internal tracing in libpdx. This is disabled by default to avoid |
23 | #ifndef PDX_TRACE_ENABLED | 9 | // spamming the trace buffers during normal trace activities. libpdx must be |
24 | #define PDX_TRACE_ENABLED 0 | 10 | // built with this set to true to enable internal tracing. |
11 | #ifndef PDX_LIB_TRACE_ENABLED | ||
12 | #define PDX_LIB_TRACE_ENABLED false | ||
25 | #endif | 13 | #endif |
26 | 14 | ||
27 | #if (ATRACE_TAG) != (ATRACE_TAG_NEVER) && (PDX_TRACE_ENABLED) | 15 | namespace android { |
28 | #define PDX_TRACE_NAME ATRACE_NAME | 16 | namespace pdx { |
29 | #else | 17 | |
30 | #define PDX_TRACE_NAME(name) \ | 18 | // Utility to generate scoped tracers with arguments. |
31 | do { \ | 19 | class ScopedTraceArgs { |
32 | } while (0) | 20 | public: |
33 | #endif | 21 | template <typename... Args> |
22 | ScopedTraceArgs(uint64_t tag, const char* format, Args&&... args) | ||
23 | : tag_{tag} { | ||
24 | if (atrace_is_tag_enabled(tag_)) { | ||
25 | std::array<char, 1024> buffer; | ||
26 | snprintf(buffer.data(), buffer.size(), format, | ||
27 | std::forward<Args>(args)...); | ||
28 | atrace_begin(tag_, buffer.data()); | ||
29 | } | ||
30 | } | ||
31 | |||
32 | ~ScopedTraceArgs() { atrace_end(tag_); } | ||
33 | |||
34 | private: | ||
35 | uint64_t tag_; | ||
36 | |||
37 | ScopedTraceArgs(const ScopedTraceArgs&) = delete; | ||
38 | void operator=(const ScopedTraceArgs&) = delete; | ||
39 | }; | ||
40 | |||
41 | // Utility to generate scoped tracers. | ||
42 | class ScopedTrace { | ||
43 | public: | ||
44 | template <typename... Args> | ||
45 | ScopedTrace(uint64_t tag, bool enabled, const char* name) | ||
46 | : tag_{tag}, enabled_{enabled} { | ||
47 | if (enabled_) | ||
48 | atrace_begin(tag_, name); | ||
49 | } | ||
50 | |||
51 | ~ScopedTrace() { | ||
52 | if (enabled_) | ||
53 | atrace_end(tag_); | ||
54 | } | ||
55 | |||
56 | private: | ||
57 | uint64_t tag_; | ||
58 | bool enabled_; | ||
59 | |||
60 | ScopedTrace(const ScopedTrace&) = delete; | ||
61 | void operator=(const ScopedTrace&) = delete; | ||
62 | }; | ||
63 | |||
64 | } // namespace pdx | ||
65 | } // namespace android | ||
66 | |||
67 | // Macro to define a scoped tracer with arguments. Uses PASTE(x, y) macro | ||
68 | // defined in utils/Trace.h. | ||
69 | #define PDX_TRACE_FORMAT(format, ...) \ | ||
70 | ::android::pdx::ScopedTraceArgs PASTE(__tracer, __LINE__) { \ | ||
71 | ATRACE_TAG, format, ##__VA_ARGS__ \ | ||
72 | } | ||
73 | |||
74 | // TODO(eieio): Rename this to PDX_LIB_TRACE_NAME() for internal use by libpdx | ||
75 | // and rename internal uses inside the library. This version is only enabled | ||
76 | // when PDX_LIB_TRACE_ENABLED is true. | ||
77 | #define PDX_TRACE_NAME(name) \ | ||
78 | ::android::pdx::ScopedTrace PASTE(__tracer, __LINE__) { \ | ||
79 | ATRACE_TAG, PDX_LIB_TRACE_ENABLED, name \ | ||
80 | } | ||
34 | 81 | ||
35 | #endif // ANDROID_PDX_TRACE_H_ | 82 | #endif // ANDROID_PDX_TRACE_H_ |
diff --git a/libs/vr/libpdx_uds/channel_event_set.cpp b/libs/vr/libpdx_uds/channel_event_set.cpp index ebe7cea7e..c68968e1f 100644 --- a/libs/vr/libpdx_uds/channel_event_set.cpp +++ b/libs/vr/libpdx_uds/channel_event_set.cpp | |||
@@ -1,6 +1,10 @@ | |||
1 | #include "private/uds/channel_event_set.h" | 1 | #include "private/uds/channel_event_set.h" |
2 | 2 | ||
3 | #include <errno.h> | ||
3 | #include <log/log.h> | 4 | #include <log/log.h> |
5 | #include <poll.h> | ||
6 | #include <sys/epoll.h> | ||
7 | #include <sys/eventfd.h> | ||
4 | 8 | ||
5 | #include <uds/ipc_helper.h> | 9 | #include <uds/ipc_helper.h> |
6 | 10 | ||
@@ -8,109 +12,137 @@ namespace android { | |||
8 | namespace pdx { | 12 | namespace pdx { |
9 | namespace uds { | 13 | namespace uds { |
10 | 14 | ||
15 | namespace { | ||
16 | |||
17 | template <typename FileHandleType> | ||
18 | Status<void> SetupHandle(int fd, FileHandleType* handle, | ||
19 | const char* error_name) { | ||
20 | const int error = errno; | ||
21 | handle->Reset(fd); | ||
22 | if (!*handle) { | ||
23 | ALOGE("SetupHandle: Failed to setup %s handle: %s", error_name, | ||
24 | strerror(error)); | ||
25 | return ErrorStatus{error}; | ||
26 | } | ||
27 | return {}; | ||
28 | } | ||
29 | |||
30 | } // anonymous namespace | ||
31 | |||
11 | ChannelEventSet::ChannelEventSet() { | 32 | ChannelEventSet::ChannelEventSet() { |
12 | const int flags = EFD_CLOEXEC | EFD_NONBLOCK; | 33 | const int flags = EFD_CLOEXEC | EFD_NONBLOCK; |
13 | LocalHandle epoll_fd, event_fd; | 34 | LocalHandle pollin_event_fd, pollhup_event_fd; |
14 | 35 | ||
15 | if (!SetupHandle(epoll_create1(EPOLL_CLOEXEC), &epoll_fd, "epoll") || | 36 | if (!SetupHandle(eventfd(0, flags), &pollin_event_fd, "pollin_event") || |
16 | !SetupHandle(eventfd(0, flags), &event_fd, "event")) { | 37 | !SetupHandle(eventfd(0, flags), &pollhup_event_fd, "pollhup_event")) { |
38 | return; | ||
39 | } | ||
40 | |||
41 | pollin_event_fd_ = std::move(pollin_event_fd); | ||
42 | pollhup_event_fd_ = std::move(pollhup_event_fd); | ||
43 | } | ||
44 | |||
45 | int ChannelEventSet::ModifyEvents(int clear_mask, int set_mask) { | ||
46 | ALOGD_IF(TRACE, "ChannelEventSet::ModifyEvents: clear_mask=%x set_mask=%x", | ||
47 | clear_mask, set_mask); | ||
48 | const int old_bits = event_bits_; | ||
49 | const int new_bits = (event_bits_ & ~clear_mask) | set_mask; | ||
50 | event_bits_ = new_bits; | ||
51 | eventfd_t value; | ||
52 | |||
53 | // Calculate which bits changed and how. Bits that haven't changed since last | ||
54 | // modification will not change the state of an eventfd. | ||
55 | const int set_bits = new_bits & ~old_bits; | ||
56 | const int clear_bits = ~new_bits & old_bits; | ||
57 | |||
58 | if (set_bits & EPOLLIN) | ||
59 | eventfd_write(pollin_event_fd_.Get(), 1); | ||
60 | else if (clear_bits & EPOLLIN) | ||
61 | eventfd_read(pollin_event_fd_.Get(), &value); | ||
62 | |||
63 | if (set_bits & EPOLLHUP) | ||
64 | eventfd_write(pollhup_event_fd_.Get(), 1); | ||
65 | else if (clear_bits & EPOLLHUP) | ||
66 | eventfd_read(pollhup_event_fd_.Get(), &value); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | ChannelEventReceiver::ChannelEventReceiver(LocalHandle data_fd, | ||
72 | LocalHandle pollin_event_fd, | ||
73 | LocalHandle pollhup_event_fd) { | ||
74 | LocalHandle epoll_fd; | ||
75 | if (!SetupHandle(epoll_create1(EPOLL_CLOEXEC), &epoll_fd, "epoll")) { | ||
17 | return; | 76 | return; |
18 | } | 77 | } |
19 | 78 | ||
20 | epoll_event event; | 79 | epoll_event event; |
21 | event.events = 0; | 80 | event.events = EPOLLHUP | EPOLLRDHUP; |
22 | event.data.u32 = 0; | 81 | event.data.u32 = 0; |
23 | if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_fd.Get(), &event) < 0) { | 82 | if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, data_fd.Get(), &event) < 0) { |
24 | const int error = errno; | 83 | const int error = errno; |
25 | ALOGE("ChannelEventSet::ChannelEventSet: Failed to add event_fd: %s", | 84 | ALOGE("ChannelEventSet::ChannelEventSet: Failed to add data_fd: %s", |
26 | strerror(error)); | 85 | strerror(error)); |
27 | return; | 86 | return; |
28 | } | 87 | } |
29 | 88 | ||
30 | epoll_fd_ = std::move(epoll_fd); | 89 | event.events = EPOLLIN; |
31 | event_fd_ = std::move(event_fd); | 90 | event.data.u32 = 0; |
32 | } | 91 | if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, pollin_event_fd.Get(), &event) < |
33 | 92 | 0) { | |
34 | Status<void> ChannelEventSet::AddDataFd(const LocalHandle& data_fd) { | ||
35 | epoll_event event; | ||
36 | event.events = EPOLLHUP | EPOLLRDHUP; | ||
37 | event.data.u32 = event.events; | ||
38 | if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, data_fd.Get(), &event) < 0) { | ||
39 | const int error = errno; | 93 | const int error = errno; |
40 | ALOGE("ChannelEventSet::ChannelEventSet: Failed to add event_fd: %s", | 94 | ALOGE("ChannelEventSet::ChannelEventSet: Failed to add pollin_event_fd: %s", |
41 | strerror(error)); | 95 | strerror(error)); |
42 | return ErrorStatus{error}; | 96 | return; |
43 | } else { | ||
44 | return {}; | ||
45 | } | 97 | } |
46 | } | ||
47 | 98 | ||
48 | int ChannelEventSet::ModifyEvents(int clear_mask, int set_mask) { | 99 | event.events = EPOLLIN; |
49 | ALOGD_IF(TRACE, "ChannelEventSet::ModifyEvents: clear_mask=%x set_mask=%x", | 100 | event.data.u32 = 0; |
50 | clear_mask, set_mask); | 101 | if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, pollhup_event_fd.Get(), &event) < |
51 | const int old_bits = event_bits_; | 102 | 0) { |
52 | const int new_bits = (event_bits_ & ~clear_mask) | set_mask; | 103 | const int error = errno; |
53 | event_bits_ = new_bits; | 104 | ALOGE( |
54 | 105 | "ChannelEventSet::ChannelEventSet: Failed to add pollhup_event_fd: %s", | |
55 | // If anything changed clear the event and update the event mask. | 106 | strerror(error)); |
56 | if (old_bits != new_bits) { | 107 | return; |
57 | eventfd_t value; | ||
58 | eventfd_read(event_fd_.Get(), &value); | ||
59 | |||
60 | epoll_event event; | ||
61 | event.events = POLLIN; | ||
62 | event.data.u32 = event_bits_; | ||
63 | if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_MOD, event_fd_.Get(), &event) < | ||
64 | 0) { | ||
65 | const int error = errno; | ||
66 | ALOGE("ChannelEventSet::AddEventHandle: Failed to update event: %s", | ||
67 | strerror(error)); | ||
68 | return -error; | ||
69 | } | ||
70 | } | 108 | } |
71 | 109 | ||
72 | // If there are any bits set, re-trigger the eventfd. | 110 | pollin_event_fd_ = std::move(pollin_event_fd); |
73 | if (new_bits) | 111 | pollhup_event_fd_ = std::move(pollhup_event_fd); |
74 | eventfd_write(event_fd_.Get(), 1); | 112 | data_fd_ = std::move(data_fd); |
75 | 113 | epoll_fd_ = std::move(epoll_fd); | |
76 | return 0; | ||
77 | } | 114 | } |
78 | 115 | ||
79 | Status<void> ChannelEventSet::SetupHandle(int fd, LocalHandle* handle, | 116 | Status<int> ChannelEventReceiver::PollPendingEvents(int timeout_ms) const { |
80 | const char* error_name) { | 117 | std::array<pollfd, 3> pfds = {{{pollin_event_fd_.Get(), POLLIN, 0}, |
81 | const int error = errno; | 118 | {pollhup_event_fd_.Get(), POLLIN, 0}, |
82 | handle->Reset(fd); | 119 | {data_fd_.Get(), POLLHUP | POLLRDHUP, 0}}}; |
83 | if (!*handle) { | 120 | if (RETRY_EINTR(poll(pfds.data(), pfds.size(), timeout_ms)) < 0) { |
84 | ALOGE("ChannelEventSet::SetupHandle: Failed to setup %s handle: %s", | 121 | const int error = errno; |
85 | error_name, strerror(error)); | 122 | ALOGE( |
123 | "ChannelEventReceiver::PollPendingEvents: Failed to poll for events: " | ||
124 | "%s", | ||
125 | strerror(error)); | ||
86 | return ErrorStatus{error}; | 126 | return ErrorStatus{error}; |
87 | } | 127 | } |
88 | return {}; | 128 | |
129 | const int event_mask = | ||
130 | ((pfds[0].revents & POLLIN) ? EPOLLIN : 0) | | ||
131 | ((pfds[1].revents & POLLIN) ? EPOLLHUP : 0) | | ||
132 | ((pfds[2].revents & (POLLHUP | POLLRDHUP)) ? EPOLLHUP : 0); | ||
133 | return {event_mask}; | ||
89 | } | 134 | } |
90 | 135 | ||
91 | Status<int> ChannelEventReceiver::GetPendingEvents() const { | 136 | Status<int> ChannelEventReceiver::GetPendingEvents() const { |
92 | constexpr long kTimeoutMs = 0; | 137 | constexpr long kTimeoutMs = 0; |
93 | epoll_event event; | 138 | return PollPendingEvents(kTimeoutMs); |
94 | const int count = | 139 | } |
95 | RETRY_EINTR(epoll_wait(epoll_fd_.Get(), &event, 1, kTimeoutMs)); | ||
96 | |||
97 | Status<int> status; | ||
98 | if (count < 0) { | ||
99 | status.SetError(errno); | ||
100 | ALOGE("ChannelEventReceiver::GetPendingEvents: Failed to get events: %s", | ||
101 | status.GetErrorMessage().c_str()); | ||
102 | return status; | ||
103 | } else if (count == 0) { | ||
104 | status.SetError(ETIMEDOUT); | ||
105 | return status; | ||
106 | } | ||
107 | |||
108 | const int mask_out = event.data.u32; | ||
109 | ALOGD_IF(TRACE, "ChannelEventReceiver::GetPendingEvents: mask_out=%x", | ||
110 | mask_out); | ||
111 | 140 | ||
112 | status.SetValue(mask_out); | 141 | std::vector<ClientChannel::EventSource> ChannelEventReceiver::GetEventSources() |
113 | return status; | 142 | const { |
143 | return {{data_fd_.Get(), EPOLLHUP | EPOLLRDHUP}, | ||
144 | {pollin_event_fd_.Get(), EPOLLIN}, | ||
145 | {pollhup_event_fd_.Get(), POLLIN}}; | ||
114 | } | 146 | } |
115 | 147 | ||
116 | } // namespace uds | 148 | } // namespace uds |
diff --git a/libs/vr/libpdx_uds/channel_manager.cpp b/libs/vr/libpdx_uds/channel_manager.cpp index afc0a4f04..43ebe0502 100644 --- a/libs/vr/libpdx_uds/channel_manager.cpp +++ b/libs/vr/libpdx_uds/channel_manager.cpp | |||
@@ -22,18 +22,26 @@ void ChannelManager::CloseHandle(int32_t handle) { | |||
22 | } | 22 | } |
23 | 23 | ||
24 | LocalChannelHandle ChannelManager::CreateHandle(LocalHandle data_fd, | 24 | LocalChannelHandle ChannelManager::CreateHandle(LocalHandle data_fd, |
25 | LocalHandle event_fd) { | 25 | LocalHandle pollin_event_fd, |
26 | if (data_fd && event_fd) { | 26 | LocalHandle pollhup_event_fd) { |
27 | if (data_fd && pollin_event_fd && pollhup_event_fd) { | ||
27 | std::lock_guard<std::mutex> autolock(mutex_); | 28 | std::lock_guard<std::mutex> autolock(mutex_); |
28 | int32_t handle = data_fd.Get(); | 29 | const int32_t handle = data_fd.Get(); |
29 | channels_.emplace(handle, | 30 | channels_.emplace( |
30 | ChannelData{std::move(data_fd), std::move(event_fd)}); | 31 | handle, |
32 | ChannelEventReceiver{std::move(data_fd), std::move(pollin_event_fd), | ||
33 | std::move(pollhup_event_fd)}); | ||
31 | return LocalChannelHandle(this, handle); | 34 | return LocalChannelHandle(this, handle); |
35 | } else { | ||
36 | ALOGE( | ||
37 | "ChannelManager::CreateHandle: Invalid arguments: data_fd=%d " | ||
38 | "pollin_event_fd=%d pollhup_event_fd=%d", | ||
39 | data_fd.Get(), pollin_event_fd.Get(), pollhup_event_fd.Get()); | ||
40 | return LocalChannelHandle(nullptr, -1); | ||
32 | } | 41 | } |
33 | return LocalChannelHandle(nullptr, -1); | ||
34 | } | 42 | } |
35 | 43 | ||
36 | ChannelManager::ChannelData* ChannelManager::GetChannelData(int32_t handle) { | 44 | ChannelEventReceiver* ChannelManager::GetChannelData(int32_t handle) { |
37 | std::lock_guard<std::mutex> autolock(mutex_); | 45 | std::lock_guard<std::mutex> autolock(mutex_); |
38 | auto channel = channels_.find(handle); | 46 | auto channel = channels_.find(handle); |
39 | return channel != channels_.end() ? &channel->second : nullptr; | 47 | return channel != channels_.end() ? &channel->second : nullptr; |
diff --git a/libs/vr/libpdx_uds/client_channel.cpp b/libs/vr/libpdx_uds/client_channel.cpp index 3f785fa62..2e9c1def3 100644 --- a/libs/vr/libpdx_uds/client_channel.cpp +++ b/libs/vr/libpdx_uds/client_channel.cpp | |||
@@ -33,7 +33,9 @@ struct TransactionState { | |||
33 | } else if (static_cast<size_t>(index) < response.channels.size()) { | 33 | } else if (static_cast<size_t>(index) < response.channels.size()) { |
34 | auto& channel_info = response.channels[index]; | 34 | auto& channel_info = response.channels[index]; |
35 | *handle = ChannelManager::Get().CreateHandle( | 35 | *handle = ChannelManager::Get().CreateHandle( |
36 | std::move(channel_info.data_fd), std::move(channel_info.event_fd)); | 36 | std::move(channel_info.data_fd), |
37 | std::move(channel_info.pollin_event_fd), | ||
38 | std::move(channel_info.pollhup_event_fd)); | ||
37 | } else { | 39 | } else { |
38 | return false; | 40 | return false; |
39 | } | 41 | } |
@@ -53,9 +55,9 @@ struct TransactionState { | |||
53 | 55 | ||
54 | if (auto* channel_data = | 56 | if (auto* channel_data = |
55 | ChannelManager::Get().GetChannelData(handle.value())) { | 57 | ChannelManager::Get().GetChannelData(handle.value())) { |
56 | ChannelInfo<BorrowedHandle> channel_info; | 58 | ChannelInfo<BorrowedHandle> channel_info{ |
57 | channel_info.data_fd.Reset(handle.value()); | 59 | channel_data->data_fd(), channel_data->pollin_event_fd(), |
58 | channel_info.event_fd = channel_data->event_receiver.event_fd(); | 60 | channel_data->pollhup_event_fd()}; |
59 | request.channels.push_back(std::move(channel_info)); | 61 | request.channels.push_back(std::move(channel_info)); |
60 | return request.channels.size() - 1; | 62 | return request.channels.size() - 1; |
61 | } else { | 63 | } else { |
diff --git a/libs/vr/libpdx_uds/client_channel_factory.cpp b/libs/vr/libpdx_uds/client_channel_factory.cpp index 433f45976..09dc7beb7 100644 --- a/libs/vr/libpdx_uds/client_channel_factory.cpp +++ b/libs/vr/libpdx_uds/client_channel_factory.cpp | |||
@@ -139,20 +139,33 @@ Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect( | |||
139 | 139 | ||
140 | RequestHeader<BorrowedHandle> request; | 140 | RequestHeader<BorrowedHandle> request; |
141 | InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false); | 141 | InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false); |
142 | |||
142 | status = SendData(socket_.Borrow(), request); | 143 | status = SendData(socket_.Borrow(), request); |
143 | if (!status) | 144 | if (!status) |
144 | return status.error_status(); | 145 | return status.error_status(); |
146 | |||
145 | ResponseHeader<LocalHandle> response; | 147 | ResponseHeader<LocalHandle> response; |
146 | status = ReceiveData(socket_.Borrow(), &response); | 148 | status = ReceiveData(socket_.Borrow(), &response); |
147 | if (!status) | 149 | if (!status) |
148 | return status.error_status(); | 150 | return status.error_status(); |
149 | int ref = response.ret_code; | 151 | else if (response.ret_code < 0 || response.channels.size() != 1) |
150 | if (ref < 0 || static_cast<size_t>(ref) > response.file_descriptors.size()) | 152 | return ErrorStatus(EIO); |
153 | |||
154 | LocalHandle pollin_event_fd = std::move(response.channels[0].pollin_event_fd); | ||
155 | LocalHandle pollhup_event_fd = | ||
156 | std::move(response.channels[0].pollhup_event_fd); | ||
157 | |||
158 | if (!pollin_event_fd || !pollhup_event_fd) { | ||
159 | ALOGE( | ||
160 | "ClientChannelFactory::Connect: Required fd was not returned from the " | ||
161 | "service: pollin_event_fd=%d pollhup_event_fd=%d", | ||
162 | pollin_event_fd.Get(), pollhup_event_fd.Get()); | ||
151 | return ErrorStatus(EIO); | 163 | return ErrorStatus(EIO); |
164 | } | ||
152 | 165 | ||
153 | LocalHandle event_fd = std::move(response.file_descriptors[ref]); | ||
154 | return ClientChannel::Create(ChannelManager::Get().CreateHandle( | 166 | return ClientChannel::Create(ChannelManager::Get().CreateHandle( |
155 | std::move(socket_), std::move(event_fd))); | 167 | std::move(socket_), std::move(pollin_event_fd), |
168 | std::move(pollhup_event_fd))); | ||
156 | } | 169 | } |
157 | 170 | ||
158 | } // namespace uds | 171 | } // namespace uds |
diff --git a/libs/vr/libpdx_uds/private/uds/channel_event_set.h b/libs/vr/libpdx_uds/private/uds/channel_event_set.h index 1f464d5f9..99e75028d 100644 --- a/libs/vr/libpdx_uds/private/uds/channel_event_set.h +++ b/libs/vr/libpdx_uds/private/uds/channel_event_set.h | |||
@@ -1,11 +1,9 @@ | |||
1 | #ifndef ANDROID_PDX_UDS_CHANNEL_EVENT_SET_H_ | 1 | #ifndef ANDROID_PDX_UDS_CHANNEL_EVENT_SET_H_ |
2 | #define ANDROID_PDX_UDS_CHANNEL_EVENT_SET_H_ | 2 | #define ANDROID_PDX_UDS_CHANNEL_EVENT_SET_H_ |
3 | 3 | ||
4 | #include <errno.h> | 4 | #include <vector> |
5 | #include <poll.h> | ||
6 | #include <sys/epoll.h> | ||
7 | #include <sys/eventfd.h> | ||
8 | 5 | ||
6 | #include <pdx/client_channel.h> | ||
9 | #include <pdx/file_handle.h> | 7 | #include <pdx/file_handle.h> |
10 | #include <pdx/status.h> | 8 | #include <pdx/status.h> |
11 | 9 | ||
@@ -19,21 +17,20 @@ class ChannelEventSet { | |||
19 | ChannelEventSet(ChannelEventSet&&) = default; | 17 | ChannelEventSet(ChannelEventSet&&) = default; |
20 | ChannelEventSet& operator=(ChannelEventSet&&) = default; | 18 | ChannelEventSet& operator=(ChannelEventSet&&) = default; |
21 | 19 | ||
22 | BorrowedHandle event_fd() const { return epoll_fd_.Borrow(); } | 20 | BorrowedHandle pollin_event_fd() const { return pollin_event_fd_.Borrow(); } |
21 | BorrowedHandle pollhup_event_fd() const { return pollhup_event_fd_.Borrow(); } | ||
23 | 22 | ||
24 | explicit operator bool() const { return !!epoll_fd_ && !!event_fd_; } | 23 | explicit operator bool() const { |
24 | return !!pollin_event_fd_ && !!pollhup_event_fd_; | ||
25 | } | ||
25 | 26 | ||
26 | Status<void> AddDataFd(const LocalHandle& data_fd); | ||
27 | int ModifyEvents(int clear_mask, int set_mask); | 27 | int ModifyEvents(int clear_mask, int set_mask); |
28 | 28 | ||
29 | private: | 29 | private: |
30 | LocalHandle epoll_fd_; | 30 | LocalHandle pollin_event_fd_; |
31 | LocalHandle event_fd_; | 31 | LocalHandle pollhup_event_fd_; |
32 | uint32_t event_bits_ = 0; | 32 | uint32_t event_bits_ = 0; |
33 | 33 | ||
34 | static Status<void> SetupHandle(int fd, LocalHandle* handle, | ||
35 | const char* error_name); | ||
36 | |||
37 | ChannelEventSet(const ChannelEventSet&) = delete; | 34 | ChannelEventSet(const ChannelEventSet&) = delete; |
38 | void operator=(const ChannelEventSet&) = delete; | 35 | void operator=(const ChannelEventSet&) = delete; |
39 | }; | 36 | }; |
@@ -41,14 +38,31 @@ class ChannelEventSet { | |||
41 | class ChannelEventReceiver { | 38 | class ChannelEventReceiver { |
42 | public: | 39 | public: |
43 | ChannelEventReceiver() = default; | 40 | ChannelEventReceiver() = default; |
44 | ChannelEventReceiver(LocalHandle epoll_fd) : epoll_fd_{std::move(epoll_fd)} {} | 41 | ChannelEventReceiver(LocalHandle data_fd, LocalHandle pollin_event_fd, |
42 | LocalHandle pollhup_event_fd); | ||
45 | ChannelEventReceiver(ChannelEventReceiver&&) = default; | 43 | ChannelEventReceiver(ChannelEventReceiver&&) = default; |
46 | ChannelEventReceiver& operator=(ChannelEventReceiver&&) = default; | 44 | ChannelEventReceiver& operator=(ChannelEventReceiver&&) = default; |
47 | 45 | ||
46 | explicit operator bool() const { | ||
47 | return !!pollin_event_fd_ && !!pollhup_event_fd_ && !!data_fd_ && | ||
48 | !!epoll_fd_; | ||
49 | } | ||
50 | |||
48 | BorrowedHandle event_fd() const { return epoll_fd_.Borrow(); } | 51 | BorrowedHandle event_fd() const { return epoll_fd_.Borrow(); } |
52 | |||
53 | BorrowedHandle pollin_event_fd() const { return pollin_event_fd_.Borrow(); } | ||
54 | BorrowedHandle pollhup_event_fd() const { return pollhup_event_fd_.Borrow(); } | ||
55 | BorrowedHandle data_fd() const { return data_fd_.Borrow(); } | ||
56 | |||
49 | Status<int> GetPendingEvents() const; | 57 | Status<int> GetPendingEvents() const; |
58 | Status<int> PollPendingEvents(int timeout_ms) const; | ||
59 | |||
60 | std::vector<ClientChannel::EventSource> GetEventSources() const; | ||
50 | 61 | ||
51 | private: | 62 | private: |
63 | LocalHandle data_fd_; | ||
64 | LocalHandle pollin_event_fd_; | ||
65 | LocalHandle pollhup_event_fd_; | ||
52 | LocalHandle epoll_fd_; | 66 | LocalHandle epoll_fd_; |
53 | 67 | ||
54 | ChannelEventReceiver(const ChannelEventReceiver&) = delete; | 68 | ChannelEventReceiver(const ChannelEventReceiver&) = delete; |
diff --git a/libs/vr/libpdx_uds/private/uds/channel_manager.h b/libs/vr/libpdx_uds/private/uds/channel_manager.h index 2aca41421..5f6a51434 100644 --- a/libs/vr/libpdx_uds/private/uds/channel_manager.h +++ b/libs/vr/libpdx_uds/private/uds/channel_manager.h | |||
@@ -16,13 +16,11 @@ class ChannelManager : public ChannelManagerInterface { | |||
16 | public: | 16 | public: |
17 | static ChannelManager& Get(); | 17 | static ChannelManager& Get(); |
18 | 18 | ||
19 | LocalChannelHandle CreateHandle(LocalHandle data_fd, LocalHandle event_fd); | 19 | LocalChannelHandle CreateHandle(LocalHandle data_fd, |
20 | struct ChannelData { | 20 | LocalHandle pollin_event_fd, |
21 | LocalHandle data_fd; | 21 | LocalHandle pollhup_event_fd); |
22 | ChannelEventReceiver event_receiver; | ||
23 | }; | ||
24 | 22 | ||
25 | ChannelData* GetChannelData(int32_t handle); | 23 | ChannelEventReceiver* GetChannelData(int32_t handle); |
26 | 24 | ||
27 | private: | 25 | private: |
28 | ChannelManager() = default; | 26 | ChannelManager() = default; |
@@ -30,7 +28,7 @@ class ChannelManager : public ChannelManagerInterface { | |||
30 | void CloseHandle(int32_t handle) override; | 28 | void CloseHandle(int32_t handle) override; |
31 | 29 | ||
32 | std::mutex mutex_; | 30 | std::mutex mutex_; |
33 | std::unordered_map<int32_t, ChannelData> channels_; | 31 | std::unordered_map<int32_t, ChannelEventReceiver> channels_; |
34 | }; | 32 | }; |
35 | 33 | ||
36 | } // namespace uds | 34 | } // namespace uds |
diff --git a/libs/vr/libpdx_uds/private/uds/client_channel.h b/libs/vr/libpdx_uds/private/uds/client_channel.h index 8f607f56a..7a5ddf40e 100644 --- a/libs/vr/libpdx_uds/private/uds/client_channel.h +++ b/libs/vr/libpdx_uds/private/uds/client_channel.h | |||
@@ -23,11 +23,19 @@ class ClientChannel : public pdx::ClientChannel { | |||
23 | uint32_t GetIpcTag() const override { return Endpoint::kIpcTag; } | 23 | uint32_t GetIpcTag() const override { return Endpoint::kIpcTag; } |
24 | 24 | ||
25 | int event_fd() const override { | 25 | int event_fd() const override { |
26 | return channel_data_ ? channel_data_->event_receiver.event_fd().Get() : -1; | 26 | return channel_data_ ? channel_data_->event_fd().Get() : -1; |
27 | } | 27 | } |
28 | |||
29 | std::vector<EventSource> GetEventSources() const override { | ||
30 | if (channel_data_) | ||
31 | return channel_data_->GetEventSources(); | ||
32 | else | ||
33 | return {}; | ||
34 | } | ||
35 | |||
28 | Status<int> GetEventMask(int /*events*/) override { | 36 | Status<int> GetEventMask(int /*events*/) override { |
29 | if (channel_data_) | 37 | if (channel_data_) |
30 | return channel_data_->event_receiver.GetPendingEvents(); | 38 | return channel_data_->GetPendingEvents(); |
31 | else | 39 | else |
32 | return ErrorStatus(EINVAL); | 40 | return ErrorStatus(EINVAL); |
33 | } | 41 | } |
@@ -74,7 +82,7 @@ class ClientChannel : public pdx::ClientChannel { | |||
74 | const iovec* receive_vector, size_t receive_count); | 82 | const iovec* receive_vector, size_t receive_count); |
75 | 83 | ||
76 | LocalChannelHandle channel_handle_; | 84 | LocalChannelHandle channel_handle_; |
77 | ChannelManager::ChannelData* channel_data_; | 85 | ChannelEventReceiver* channel_data_; |
78 | std::mutex socket_mutex_; | 86 | std::mutex socket_mutex_; |
79 | }; | 87 | }; |
80 | 88 | ||
diff --git a/libs/vr/libpdx_uds/private/uds/ipc_helper.h b/libs/vr/libpdx_uds/private/uds/ipc_helper.h index 664a0d1a1..63b5b1078 100644 --- a/libs/vr/libpdx_uds/private/uds/ipc_helper.h +++ b/libs/vr/libpdx_uds/private/uds/ipc_helper.h | |||
@@ -110,10 +110,12 @@ template <typename FileHandleType> | |||
110 | class ChannelInfo { | 110 | class ChannelInfo { |
111 | public: | 111 | public: |
112 | FileHandleType data_fd; | 112 | FileHandleType data_fd; |
113 | FileHandleType event_fd; | 113 | FileHandleType pollin_event_fd; |
114 | FileHandleType pollhup_event_fd; | ||
114 | 115 | ||
115 | private: | 116 | private: |
116 | PDX_SERIALIZABLE_MEMBERS(ChannelInfo, data_fd, event_fd); | 117 | PDX_SERIALIZABLE_MEMBERS(ChannelInfo, data_fd, pollin_event_fd, |
118 | pollhup_event_fd); | ||
117 | }; | 119 | }; |
118 | 120 | ||
119 | template <typename FileHandleType> | 121 | template <typename FileHandleType> |
diff --git a/libs/vr/libpdx_uds/private/uds/service_endpoint.h b/libs/vr/libpdx_uds/private/uds/service_endpoint.h index a16381270..01ebf6519 100644 --- a/libs/vr/libpdx_uds/private/uds/service_endpoint.h +++ b/libs/vr/libpdx_uds/private/uds/service_endpoint.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <mutex> | 7 | #include <mutex> |
8 | #include <string> | 8 | #include <string> |
9 | #include <unordered_map> | 9 | #include <unordered_map> |
10 | #include <utility> | ||
10 | #include <vector> | 11 | #include <vector> |
11 | 12 | ||
12 | #include <pdx/service.h> | 13 | #include <pdx/service.h> |
@@ -139,7 +140,8 @@ class Endpoint : public pdx::Endpoint { | |||
139 | Status<void> ReenableEpollEvent(const BorrowedHandle& channel_fd); | 140 | Status<void> ReenableEpollEvent(const BorrowedHandle& channel_fd); |
140 | Channel* GetChannelState(int32_t channel_id); | 141 | Channel* GetChannelState(int32_t channel_id); |
141 | BorrowedHandle GetChannelSocketFd(int32_t channel_id); | 142 | BorrowedHandle GetChannelSocketFd(int32_t channel_id); |
142 | BorrowedHandle GetChannelEventFd(int32_t channel_id); | 143 | Status<std::pair<BorrowedHandle, BorrowedHandle>> GetChannelEventFd( |
144 | int32_t channel_id); | ||
143 | int32_t GetChannelId(const BorrowedHandle& channel_fd); | 145 | int32_t GetChannelId(const BorrowedHandle& channel_fd); |
144 | Status<void> CreateChannelSocketPair(LocalHandle* local_socket, | 146 | Status<void> CreateChannelSocketPair(LocalHandle* local_socket, |
145 | LocalHandle* remote_socket); | 147 | LocalHandle* remote_socket); |
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp index 27a56f9fe..0ee77f43a 100644 --- a/libs/vr/libpdx_uds/service_endpoint.cpp +++ b/libs/vr/libpdx_uds/service_endpoint.cpp | |||
@@ -49,7 +49,9 @@ struct MessageState { | |||
49 | } else if (static_cast<size_t>(index) < request.channels.size()) { | 49 | } else if (static_cast<size_t>(index) < request.channels.size()) { |
50 | auto& channel_info = request.channels[index]; | 50 | auto& channel_info = request.channels[index]; |
51 | *handle = ChannelManager::Get().CreateHandle( | 51 | *handle = ChannelManager::Get().CreateHandle( |
52 | std::move(channel_info.data_fd), std::move(channel_info.event_fd)); | 52 | std::move(channel_info.data_fd), |
53 | std::move(channel_info.pollin_event_fd), | ||
54 | std::move(channel_info.pollhup_event_fd)); | ||
53 | } else { | 55 | } else { |
54 | return false; | 56 | return false; |
55 | } | 57 | } |
@@ -69,9 +71,9 @@ struct MessageState { | |||
69 | 71 | ||
70 | if (auto* channel_data = | 72 | if (auto* channel_data = |
71 | ChannelManager::Get().GetChannelData(handle.value())) { | 73 | ChannelManager::Get().GetChannelData(handle.value())) { |
72 | ChannelInfo<BorrowedHandle> channel_info; | 74 | ChannelInfo<BorrowedHandle> channel_info{ |
73 | channel_info.data_fd.Reset(handle.value()); | 75 | channel_data->data_fd(), channel_data->pollin_event_fd(), |
74 | channel_info.event_fd = channel_data->event_receiver.event_fd(); | 76 | channel_data->pollhup_event_fd()}; |
75 | response.channels.push_back(std::move(channel_info)); | 77 | response.channels.push_back(std::move(channel_info)); |
76 | return response.channels.size() - 1; | 78 | return response.channels.size() - 1; |
77 | } else { | 79 | } else { |
@@ -80,12 +82,13 @@ struct MessageState { | |||
80 | } | 82 | } |
81 | 83 | ||
82 | Status<ChannelReference> PushChannelHandle(BorrowedHandle data_fd, | 84 | Status<ChannelReference> PushChannelHandle(BorrowedHandle data_fd, |
83 | BorrowedHandle event_fd) { | 85 | BorrowedHandle pollin_event_fd, |
84 | if (!data_fd || !event_fd) | 86 | BorrowedHandle pollhup_event_fd) { |
87 | if (!data_fd || !pollin_event_fd || !pollhup_event_fd) | ||
85 | return ErrorStatus{EINVAL}; | 88 | return ErrorStatus{EINVAL}; |
86 | ChannelInfo<BorrowedHandle> channel_info; | 89 | ChannelInfo<BorrowedHandle> channel_info{std::move(data_fd), |
87 | channel_info.data_fd = std::move(data_fd); | 90 | std::move(pollin_event_fd), |
88 | channel_info.event_fd = std::move(event_fd); | 91 | std::move(pollhup_event_fd)}; |
89 | response.channels.push_back(std::move(channel_info)); | 92 | response.channels.push_back(std::move(channel_info)); |
90 | return response.channels.size() - 1; | 93 | return response.channels.size() - 1; |
91 | } | 94 | } |
@@ -287,7 +290,6 @@ Status<std::pair<int32_t, Endpoint::ChannelData*>> Endpoint::OnNewChannelLocked( | |||
287 | return ErrorStatus(errno); | 290 | return ErrorStatus(errno); |
288 | } | 291 | } |
289 | ChannelData channel_data; | 292 | ChannelData channel_data; |
290 | channel_data.event_set.AddDataFd(channel_fd); | ||
291 | channel_data.data_fd = std::move(channel_fd); | 293 | channel_data.data_fd = std::move(channel_fd); |
292 | channel_data.channel_state = channel_state; | 294 | channel_data.channel_state = channel_state; |
293 | for (;;) { | 295 | for (;;) { |
@@ -431,18 +433,21 @@ Status<RemoteChannelHandle> Endpoint::PushChannel(Message* message, | |||
431 | return status.error_status(); | 433 | return status.error_status(); |
432 | 434 | ||
433 | std::lock_guard<std::mutex> autolock(channel_mutex_); | 435 | std::lock_guard<std::mutex> autolock(channel_mutex_); |
434 | auto channel_data = OnNewChannelLocked(std::move(local_socket), channel); | 436 | auto channel_data_status = |
435 | if (!channel_data) | 437 | OnNewChannelLocked(std::move(local_socket), channel); |
436 | return channel_data.error_status(); | 438 | if (!channel_data_status) |
437 | *channel_id = channel_data.get().first; | 439 | return channel_data_status.error_status(); |
440 | |||
441 | ChannelData* channel_data; | ||
442 | std::tie(*channel_id, channel_data) = channel_data_status.take(); | ||
438 | 443 | ||
439 | // Flags are ignored for now. | 444 | // Flags are ignored for now. |
440 | // TODO(xiaohuit): Implement those. | 445 | // TODO(xiaohuit): Implement those. |
441 | 446 | ||
442 | auto* state = static_cast<MessageState*>(message->GetState()); | 447 | auto* state = static_cast<MessageState*>(message->GetState()); |
443 | Status<ChannelReference> ref = state->PushChannelHandle( | 448 | Status<ChannelReference> ref = state->PushChannelHandle( |
444 | remote_socket.Borrow(), | 449 | remote_socket.Borrow(), channel_data->event_set.pollin_event_fd(), |
445 | channel_data.get().second->event_set.event_fd().Borrow()); | 450 | channel_data->event_set.pollhup_event_fd()); |
446 | if (!ref) | 451 | if (!ref) |
447 | return ref.error_status(); | 452 | return ref.error_status(); |
448 | state->sockets_to_close.push_back(std::move(remote_socket)); | 453 | state->sockets_to_close.push_back(std::move(remote_socket)); |
@@ -472,13 +477,15 @@ BorrowedHandle Endpoint::GetChannelSocketFd(int32_t channel_id) { | |||
472 | return handle; | 477 | return handle; |
473 | } | 478 | } |
474 | 479 | ||
475 | BorrowedHandle Endpoint::GetChannelEventFd(int32_t channel_id) { | 480 | Status<std::pair<BorrowedHandle, BorrowedHandle>> Endpoint::GetChannelEventFd( |
481 | int32_t channel_id) { | ||
476 | std::lock_guard<std::mutex> autolock(channel_mutex_); | 482 | std::lock_guard<std::mutex> autolock(channel_mutex_); |
477 | BorrowedHandle handle; | ||
478 | auto channel_data = channels_.find(channel_id); | 483 | auto channel_data = channels_.find(channel_id); |
479 | if (channel_data != channels_.end()) | 484 | if (channel_data != channels_.end()) { |
480 | handle = channel_data->second.event_set.event_fd().Borrow(); | 485 | return {{channel_data->second.event_set.pollin_event_fd(), |
481 | return handle; | 486 | channel_data->second.event_set.pollhup_event_fd()}}; |
487 | } | ||
488 | return ErrorStatus(ENOENT); | ||
482 | } | 489 | } |
483 | 490 | ||
484 | int32_t Endpoint::GetChannelId(const BorrowedHandle& channel_fd) { | 491 | int32_t Endpoint::GetChannelId(const BorrowedHandle& channel_fd) { |
@@ -593,11 +600,6 @@ Status<void> Endpoint::MessageReceive(Message* message) { | |||
593 | } | 600 | } |
594 | 601 | ||
595 | BorrowedHandle channel_fd{event.data.fd}; | 602 | BorrowedHandle channel_fd{event.data.fd}; |
596 | if (event.events & (EPOLLRDHUP | EPOLLHUP)) { | ||
597 | BuildCloseMessage(GetChannelId(channel_fd), message); | ||
598 | return {}; | ||
599 | } | ||
600 | |||
601 | return ReceiveMessageForChannel(channel_fd, message); | 603 | return ReceiveMessageForChannel(channel_fd, message); |
602 | } | 604 | } |
603 | 605 | ||
@@ -616,12 +618,23 @@ Status<void> Endpoint::MessageReply(Message* message, int return_code) { | |||
616 | if (return_code < 0) { | 618 | if (return_code < 0) { |
617 | return CloseChannel(channel_id); | 619 | return CloseChannel(channel_id); |
618 | } else { | 620 | } else { |
619 | // Reply with the event fd. | 621 | // Open messages do not have a payload and may not transfer any channels |
620 | auto push_status = state->PushFileHandle(GetChannelEventFd(channel_id)); | 622 | // or file descriptors on behalf of the service. |
621 | state->response_data.clear(); // Just in case... | 623 | state->response_data.clear(); |
622 | if (!push_status) | 624 | state->response.file_descriptors.clear(); |
623 | return push_status.error_status(); | 625 | state->response.channels.clear(); |
624 | return_code = push_status.get(); | 626 | |
627 | // Return the channel event-related fds in a single ChannelInfo entry | ||
628 | // with an empty data_fd member. | ||
629 | auto status = GetChannelEventFd(channel_id); | ||
630 | if (!status) | ||
631 | return status.error_status(); | ||
632 | |||
633 | auto handles = status.take(); | ||
634 | state->response.channels.push_back({BorrowedHandle(), | ||
635 | std::move(handles.first), | ||
636 | std::move(handles.second)}); | ||
637 | return_code = 0; | ||
625 | } | 638 | } |
626 | break; | 639 | break; |
627 | } | 640 | } |
diff --git a/libs/vr/libpdx_uds/service_framework_tests.cpp b/libs/vr/libpdx_uds/service_framework_tests.cpp index 5943b0a1b..27427162f 100644 --- a/libs/vr/libpdx_uds/service_framework_tests.cpp +++ b/libs/vr/libpdx_uds/service_framework_tests.cpp | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <errno.h> | 1 | #include <errno.h> |
2 | #include <fcntl.h> | 2 | #include <fcntl.h> |
3 | #include <poll.h> | ||
3 | #include <sys/epoll.h> | 4 | #include <sys/epoll.h> |
4 | #include <sys/eventfd.h> | 5 | #include <sys/eventfd.h> |
5 | #include <unistd.h> | 6 | #include <unistd.h> |
@@ -506,6 +507,37 @@ TEST_F(ServiceFrameworkTest, Impulse) { | |||
506 | EXPECT_EQ(-EINVAL, client->SendAsync(invalid_pointer, sizeof(int))); | 507 | EXPECT_EQ(-EINVAL, client->SendAsync(invalid_pointer, sizeof(int))); |
507 | } | 508 | } |
508 | 509 | ||
510 | // Test impulses. | ||
511 | TEST_F(ServiceFrameworkTest, ImpulseHangup) { | ||
512 | // Create a test service and add it to the dispatcher. | ||
513 | auto service = TestService::Create(kTestService1); | ||
514 | ASSERT_NE(nullptr, service); | ||
515 | ASSERT_EQ(0, dispatcher_->AddService(service)); | ||
516 | |||
517 | auto client = TestClient::Create(kTestService1); | ||
518 | ASSERT_NE(nullptr, client); | ||
519 | |||
520 | const int kMaxIterations = 1000; | ||
521 | for (int i = 0; i < kMaxIterations; i++) { | ||
522 | auto impulse_client = TestClient::Create(kTestService1); | ||
523 | ASSERT_NE(nullptr, impulse_client); | ||
524 | |||
525 | const uint8_t a = (i >> 0) & 0xff; | ||
526 | const uint8_t b = (i >> 8) & 0xff; | ||
527 | const uint8_t c = (i >> 16) & 0xff; | ||
528 | const uint8_t d = (i >> 24) & 0xff; | ||
529 | ImpulsePayload expected_payload = {{a, b, c, d}}; | ||
530 | EXPECT_EQ(0, impulse_client->SendAsync(expected_payload.data(), 4)); | ||
531 | |||
532 | // Hangup the impulse test client, then send a sync message over client to | ||
533 | // make sure the hangup message is handled before checking the impulse | ||
534 | // payload. | ||
535 | impulse_client = nullptr; | ||
536 | client->GetThisChannelId(); | ||
537 | EXPECT_EQ(expected_payload, service->GetImpulsePayload()); | ||
538 | } | ||
539 | } | ||
540 | |||
509 | // Test Message::PushChannel/Service::PushChannel API. | 541 | // Test Message::PushChannel/Service::PushChannel API. |
510 | TEST_F(ServiceFrameworkTest, PushChannel) { | 542 | TEST_F(ServiceFrameworkTest, PushChannel) { |
511 | // Create a test service and add it to the dispatcher. | 543 | // Create a test service and add it to the dispatcher. |
@@ -574,9 +606,7 @@ TEST_F(ServiceFrameworkTest, Ids) { | |||
574 | 606 | ||
575 | pid_t process_id2; | 607 | pid_t process_id2; |
576 | 608 | ||
577 | std::thread thread([&]() { | 609 | std::thread thread([&]() { process_id2 = client->GetThisProcessId(); }); |
578 | process_id2 = client->GetThisProcessId(); | ||
579 | }); | ||
580 | thread.join(); | 610 | thread.join(); |
581 | 611 | ||
582 | EXPECT_LT(2, process_id2); | 612 | EXPECT_LT(2, process_id2); |
@@ -614,15 +644,15 @@ TEST_F(ServiceFrameworkTest, PollIn) { | |||
614 | auto client = TestClient::Create(kTestService1); | 644 | auto client = TestClient::Create(kTestService1); |
615 | ASSERT_NE(nullptr, client); | 645 | ASSERT_NE(nullptr, client); |
616 | 646 | ||
617 | epoll_event event; | 647 | pollfd pfd{client->event_fd(), POLLIN, 0}; |
618 | int count = epoll_wait(client->event_fd(), &event, 1, 0); | 648 | int count = poll(&pfd, 1, 0); |
619 | ASSERT_EQ(0, count); | 649 | ASSERT_EQ(0, count); |
620 | 650 | ||
621 | client->SendPollInEvent(); | 651 | client->SendPollInEvent(); |
622 | 652 | ||
623 | count = epoll_wait(client->event_fd(), &event, 1, -1); | 653 | count = poll(&pfd, 1, 10000 /*10s*/); |
624 | ASSERT_EQ(1, count); | 654 | ASSERT_EQ(1, count); |
625 | ASSERT_TRUE((EPOLLIN & event.events) != 0); | 655 | ASSERT_TRUE((POLLIN & pfd.revents) != 0); |
626 | } | 656 | } |
627 | 657 | ||
628 | TEST_F(ServiceFrameworkTest, PollHup) { | 658 | TEST_F(ServiceFrameworkTest, PollHup) { |
@@ -635,15 +665,15 @@ TEST_F(ServiceFrameworkTest, PollHup) { | |||
635 | auto client = TestClient::Create(kTestService1); | 665 | auto client = TestClient::Create(kTestService1); |
636 | ASSERT_NE(nullptr, client); | 666 | ASSERT_NE(nullptr, client); |
637 | 667 | ||
638 | epoll_event event; | 668 | pollfd pfd{client->event_fd(), POLLIN, 0}; |
639 | int count = epoll_wait(client->event_fd(), &event, 1, 0); | 669 | int count = poll(&pfd, 1, 0); |
640 | ASSERT_EQ(0, count); | 670 | ASSERT_EQ(0, count); |
641 | 671 | ||
642 | client->SendPollHupEvent(); | 672 | client->SendPollHupEvent(); |
643 | 673 | ||
644 | count = epoll_wait(client->event_fd(), &event, 1, -1); | 674 | count = poll(&pfd, 1, 10000 /*10s*/); |
645 | ASSERT_EQ(1, count); | 675 | ASSERT_EQ(1, count); |
646 | auto event_status = client->GetEventMask(event.events); | 676 | auto event_status = client->GetEventMask(pfd.revents); |
647 | ASSERT_TRUE(event_status.ok()); | 677 | ASSERT_TRUE(event_status.ok()); |
648 | ASSERT_TRUE((EPOLLHUP & event_status.get()) != 0); | 678 | ASSERT_TRUE((EPOLLHUP & event_status.get()) != 0); |
649 | } | 679 | } |
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp index 3d132c95e..87c823e5b 100644 --- a/libs/vr/libvrflinger/display_surface.cpp +++ b/libs/vr/libvrflinger/display_surface.cpp | |||
@@ -213,8 +213,8 @@ Status<LocalChannelHandle> ApplicationDisplaySurface::OnCreateQueue( | |||
213 | ATRACE_NAME("ApplicationDisplaySurface::OnCreateQueue"); | 213 | ATRACE_NAME("ApplicationDisplaySurface::OnCreateQueue"); |
214 | ALOGD_IF(TRACE, | 214 | ALOGD_IF(TRACE, |
215 | "ApplicationDisplaySurface::OnCreateQueue: surface_id=%d, " | 215 | "ApplicationDisplaySurface::OnCreateQueue: surface_id=%d, " |
216 | "meta_size_bytes=%zu", | 216 | "user_metadata_size=%zu", |
217 | surface_id(), config.meta_size_bytes); | 217 | surface_id(), config.user_metadata_size); |
218 | 218 | ||
219 | std::lock_guard<std::mutex> autolock(lock_); | 219 | std::lock_guard<std::mutex> autolock(lock_); |
220 | auto producer = ProducerQueue::Create(config, UsagePolicy{}); | 220 | auto producer = ProducerQueue::Create(config, UsagePolicy{}); |
@@ -280,10 +280,10 @@ std::vector<int32_t> DirectDisplaySurface::GetQueueIds() const { | |||
280 | Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue( | 280 | Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue( |
281 | Message& /*message*/, const ProducerQueueConfig& config) { | 281 | Message& /*message*/, const ProducerQueueConfig& config) { |
282 | ATRACE_NAME("DirectDisplaySurface::OnCreateQueue"); | 282 | ATRACE_NAME("DirectDisplaySurface::OnCreateQueue"); |
283 | ALOGD_IF( | 283 | ALOGD_IF(TRACE, |
284 | TRACE, | 284 | "DirectDisplaySurface::OnCreateQueue: surface_id=%d " |
285 | "DirectDisplaySurface::OnCreateQueue: surface_id=%d meta_size_bytes=%zu", | 285 | "user_metadata_size=%zu", |
286 | surface_id(), config.meta_size_bytes); | 286 | surface_id(), config.user_metadata_size); |
287 | 287 | ||
288 | std::lock_guard<std::mutex> autolock(lock_); | 288 | std::lock_guard<std::mutex> autolock(lock_); |
289 | if (!direct_queue_) { | 289 | if (!direct_queue_) { |
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk index 97f0332d7..28cf53dd8 100644 --- a/services/vr/bufferhubd/Android.mk +++ b/services/vr/bufferhubd/Android.mk | |||
@@ -22,6 +22,9 @@ sourceFiles := \ | |||
22 | consumer_queue_channel.cpp \ | 22 | consumer_queue_channel.cpp \ |
23 | producer_queue_channel.cpp \ | 23 | producer_queue_channel.cpp \ |
24 | 24 | ||
25 | headerLibraries := \ | ||
26 | libdvr_headers | ||
27 | |||
25 | staticLibraries := \ | 28 | staticLibraries := \ |
26 | libperformance \ | 29 | libperformance \ |
27 | libpdx_default_transport \ | 30 | libpdx_default_transport \ |
@@ -41,6 +44,7 @@ LOCAL_SRC_FILES := $(sourceFiles) | |||
41 | LOCAL_CFLAGS := -DLOG_TAG=\"bufferhubd\" | 44 | LOCAL_CFLAGS := -DLOG_TAG=\"bufferhubd\" |
42 | LOCAL_CFLAGS += -DTRACE=0 | 45 | LOCAL_CFLAGS += -DTRACE=0 |
43 | LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_GRAPHICS | 46 | LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_GRAPHICS |
47 | LOCAL_HEADER_LIBRARIES := $(headerLibraries) | ||
44 | LOCAL_STATIC_LIBRARIES := $(staticLibraries) | 48 | LOCAL_STATIC_LIBRARIES := $(staticLibraries) |
45 | LOCAL_SHARED_LIBRARIES := $(sharedLibraries) | 49 | LOCAL_SHARED_LIBRARIES := $(sharedLibraries) |
46 | LOCAL_MODULE := bufferhubd | 50 | LOCAL_MODULE := bufferhubd |
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp index 26843c99c..cdb1f9179 100644 --- a/services/vr/bufferhubd/buffer_hub.cpp +++ b/services/vr/bufferhubd/buffer_hub.cpp | |||
@@ -20,8 +20,8 @@ using android::pdx::Channel; | |||
20 | using android::pdx::ErrorStatus; | 20 | using android::pdx::ErrorStatus; |
21 | using android::pdx::Message; | 21 | using android::pdx::Message; |
22 | using android::pdx::Status; | 22 | using android::pdx::Status; |
23 | using android::pdx::rpc::DispatchRemoteMethod; | ||
24 | using android::pdx::default_transport::Endpoint; | 23 | using android::pdx::default_transport::Endpoint; |
24 | using android::pdx::rpc::DispatchRemoteMethod; | ||
25 | 25 | ||
26 | namespace android { | 26 | namespace android { |
27 | namespace dvr { | 27 | namespace dvr { |
@@ -53,7 +53,15 @@ std::string BufferHubService::DumpState(size_t /*max_length*/) { | |||
53 | stream << " "; | 53 | stream << " "; |
54 | stream << std::setw(6) << "Format"; | 54 | stream << std::setw(6) << "Format"; |
55 | stream << " "; | 55 | stream << " "; |
56 | stream << std::setw(11) << "Usage"; | 56 | stream << std::setw(10) << "Usage"; |
57 | stream << " "; | ||
58 | stream << std::setw(9) << "Pending"; | ||
59 | stream << " "; | ||
60 | stream << std::setw(18) << "State"; | ||
61 | stream << " "; | ||
62 | stream << std::setw(18) << "Signaled"; | ||
63 | stream << " "; | ||
64 | stream << std::setw(10) << "Index"; | ||
57 | stream << " "; | 65 | stream << " "; |
58 | stream << "Name"; | 66 | stream << "Name"; |
59 | stream << std::endl; | 67 | stream << std::endl; |
@@ -83,46 +91,15 @@ std::string BufferHubService::DumpState(size_t /*max_length*/) { | |||
83 | stream << std::setw(8) << info.usage; | 91 | stream << std::setw(8) << info.usage; |
84 | stream << std::dec << std::setfill(' '); | 92 | stream << std::dec << std::setfill(' '); |
85 | stream << " "; | 93 | stream << " "; |
86 | stream << info.name; | 94 | stream << std::setw(9) << info.pending_count; |
87 | stream << std::endl; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | stream << "Active Consumer Buffers:\n"; | ||
92 | stream << std::right; | ||
93 | stream << std::setw(6) << "Id"; | ||
94 | stream << " "; | ||
95 | stream << std::setw(14) << "Geometry"; | ||
96 | stream << " "; | ||
97 | stream << "Name"; | ||
98 | stream << std::endl; | ||
99 | |||
100 | for (const auto& channel : channels) { | ||
101 | if (channel->channel_type() == BufferHubChannel::kConsumerType) { | ||
102 | BufferHubChannel::BufferInfo info = channel->GetBufferInfo(); | ||
103 | |||
104 | stream << std::right; | ||
105 | stream << std::setw(6) << info.id; | ||
106 | stream << " "; | 95 | stream << " "; |
107 | 96 | stream << "0x" << std::hex << std::setfill('0'); | |
108 | if (info.consumer_count == 0) { | 97 | stream << std::setw(16) << info.state; |
109 | // consumer_count is tracked by producer. When it's zero, producer must | 98 | stream << " "; |
110 | // have already hung up and the consumer is orphaned. | 99 | stream << "0x" << std::setw(16) << info.signaled_mask; |
111 | stream << std::setw(14) << "Orphaned."; | 100 | stream << std::dec << std::setfill(' '); |
112 | stream << (" channel_id=" + std::to_string(channel->channel_id())); | 101 | stream << " "; |
113 | stream << std::endl; | 102 | stream << std::setw(8) << info.index; |
114 | continue; | ||
115 | } | ||
116 | |||
117 | if (info.format == HAL_PIXEL_FORMAT_BLOB) { | ||
118 | std::string size = std::to_string(info.width) + " B"; | ||
119 | stream << std::setw(14) << size; | ||
120 | } else { | ||
121 | std::string dimensions = std::to_string(info.width) + "x" + | ||
122 | std::to_string(info.height) + "x" + | ||
123 | std::to_string(info.layer_count); | ||
124 | stream << std::setw(14) << dimensions; | ||
125 | } | ||
126 | stream << " "; | 103 | stream << " "; |
127 | stream << info.name; | 104 | stream << info.name; |
128 | stream << std::endl; | 105 | stream << std::endl; |
@@ -184,6 +161,32 @@ std::string BufferHubService::DumpState(size_t /*max_length*/) { | |||
184 | } | 161 | } |
185 | } | 162 | } |
186 | 163 | ||
164 | stream << std::endl; | ||
165 | stream << "Orphaned Consumer Buffers:\n"; | ||
166 | stream << std::right; | ||
167 | stream << std::setw(6) << "Id"; | ||
168 | stream << " "; | ||
169 | stream << std::setw(14) << "Geometry"; | ||
170 | stream << " "; | ||
171 | stream << "Name"; | ||
172 | stream << std::endl; | ||
173 | |||
174 | for (const auto& channel : channels) { | ||
175 | BufferHubChannel::BufferInfo info = channel->GetBufferInfo(); | ||
176 | // consumer_count is tracked by producer. When it's zero, producer must have | ||
177 | // already hung up and the consumer is orphaned. | ||
178 | if (channel->channel_type() == BufferHubChannel::kConsumerType && | ||
179 | info.consumer_count == 0) { | ||
180 | stream << std::right; | ||
181 | stream << std::setw(6) << info.id; | ||
182 | stream << " "; | ||
183 | |||
184 | stream << std::setw(14) << "Orphaned."; | ||
185 | stream << (" channel_id=" + std::to_string(channel->channel_id())); | ||
186 | stream << std::endl; | ||
187 | } | ||
188 | } | ||
189 | |||
187 | return stream.str(); | 190 | return stream.str(); |
188 | } | 191 | } |
189 | 192 | ||
@@ -444,6 +447,7 @@ void BufferHubChannel::SignalAvailable() { | |||
444 | "BufferHubChannel::SignalAvailable: channel_id=%d buffer_id=%d", | 447 | "BufferHubChannel::SignalAvailable: channel_id=%d buffer_id=%d", |
445 | channel_id(), buffer_id()); | 448 | channel_id(), buffer_id()); |
446 | if (!IsDetached()) { | 449 | if (!IsDetached()) { |
450 | signaled_ = true; | ||
447 | const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLIN); | 451 | const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLIN); |
448 | ALOGE_IF(!status, | 452 | ALOGE_IF(!status, |
449 | "BufferHubChannel::SignalAvailable: failed to signal availability " | 453 | "BufferHubChannel::SignalAvailable: failed to signal availability " |
@@ -460,6 +464,7 @@ void BufferHubChannel::ClearAvailable() { | |||
460 | "BufferHubChannel::ClearAvailable: channel_id=%d buffer_id=%d", | 464 | "BufferHubChannel::ClearAvailable: channel_id=%d buffer_id=%d", |
461 | channel_id(), buffer_id()); | 465 | channel_id(), buffer_id()); |
462 | if (!IsDetached()) { | 466 | if (!IsDetached()) { |
467 | signaled_ = false; | ||
463 | const auto status = service_->ModifyChannelEvents(channel_id_, POLLIN, 0); | 468 | const auto status = service_->ModifyChannelEvents(channel_id_, POLLIN, 0); |
464 | ALOGE_IF(!status, | 469 | ALOGE_IF(!status, |
465 | "BufferHubChannel::ClearAvailable: failed to clear availability " | 470 | "BufferHubChannel::ClearAvailable: failed to clear availability " |
diff --git a/services/vr/bufferhubd/buffer_hub.h b/services/vr/bufferhubd/buffer_hub.h index b0df11f2a..270ac9511 100644 --- a/services/vr/bufferhubd/buffer_hub.h +++ b/services/vr/bufferhubd/buffer_hub.h | |||
@@ -53,6 +53,10 @@ class BufferHubChannel : public pdx::Channel { | |||
53 | uint32_t layer_count = 0; | 53 | uint32_t layer_count = 0; |
54 | uint32_t format = 0; | 54 | uint32_t format = 0; |
55 | uint64_t usage = 0; | 55 | uint64_t usage = 0; |
56 | size_t pending_count = 0; | ||
57 | uint64_t state = 0; | ||
58 | uint64_t signaled_mask = 0; | ||
59 | uint64_t index = 0; | ||
56 | std::string name; | 60 | std::string name; |
57 | 61 | ||
58 | // Data filed for producer queue. | 62 | // Data filed for producer queue. |
@@ -60,7 +64,9 @@ class BufferHubChannel : public pdx::Channel { | |||
60 | UsagePolicy usage_policy{0, 0, 0, 0}; | 64 | UsagePolicy usage_policy{0, 0, 0, 0}; |
61 | 65 | ||
62 | BufferInfo(int id, size_t consumer_count, uint32_t width, uint32_t height, | 66 | BufferInfo(int id, size_t consumer_count, uint32_t width, uint32_t height, |
63 | uint32_t layer_count, uint32_t format, uint64_t usage, const std::string& name) | 67 | uint32_t layer_count, uint32_t format, uint64_t usage, |
68 | size_t pending_count, uint64_t state, uint64_t signaled_mask, | ||
69 | uint64_t index, const std::string& name) | ||
64 | : id(id), | 70 | : id(id), |
65 | type(kProducerType), | 71 | type(kProducerType), |
66 | consumer_count(consumer_count), | 72 | consumer_count(consumer_count), |
@@ -69,6 +75,10 @@ class BufferHubChannel : public pdx::Channel { | |||
69 | layer_count(layer_count), | 75 | layer_count(layer_count), |
70 | format(format), | 76 | format(format), |
71 | usage(usage), | 77 | usage(usage), |
78 | pending_count(pending_count), | ||
79 | state(state), | ||
80 | signaled_mask(signaled_mask), | ||
81 | index(index), | ||
72 | name(name) {} | 82 | name(name) {} |
73 | 83 | ||
74 | BufferInfo(int id, size_t consumer_count, size_t capacity, | 84 | BufferInfo(int id, size_t consumer_count, size_t capacity, |
@@ -101,6 +111,8 @@ class BufferHubChannel : public pdx::Channel { | |||
101 | int channel_id() const { return channel_id_; } | 111 | int channel_id() const { return channel_id_; } |
102 | bool IsDetached() const { return channel_id_ == kDetachedId; } | 112 | bool IsDetached() const { return channel_id_ == kDetachedId; } |
103 | 113 | ||
114 | bool signaled() const { return signaled_; } | ||
115 | |||
104 | void Detach() { | 116 | void Detach() { |
105 | if (channel_type_ == kProducerType) | 117 | if (channel_type_ == kProducerType) |
106 | channel_id_ = kDetachedId; | 118 | channel_id_ = kDetachedId; |
@@ -124,6 +136,8 @@ class BufferHubChannel : public pdx::Channel { | |||
124 | // buffer if it is detached and re-attached to another channel. | 136 | // buffer if it is detached and re-attached to another channel. |
125 | int channel_id_; | 137 | int channel_id_; |
126 | 138 | ||
139 | bool signaled_; | ||
140 | |||
127 | ChannelType channel_type_; | 141 | ChannelType channel_type_; |
128 | 142 | ||
129 | BufferHubChannel(const BufferHubChannel&) = delete; | 143 | BufferHubChannel(const BufferHubChannel&) = delete; |
diff --git a/services/vr/bufferhubd/bufferhubd.cpp b/services/vr/bufferhubd/bufferhubd.cpp index 161382129..b27f218eb 100644 --- a/services/vr/bufferhubd/bufferhubd.cpp +++ b/services/vr/bufferhubd/bufferhubd.cpp | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <unistd.h> | 2 | #include <unistd.h> |
3 | 3 | ||
4 | #include <log/log.h> | 4 | #include <log/log.h> |
5 | #include <sys/resource.h> | ||
5 | 6 | ||
6 | #include <dvr/performance_client_api.h> | 7 | #include <dvr/performance_client_api.h> |
7 | #include <pdx/service_dispatcher.h> | 8 | #include <pdx/service_dispatcher.h> |
@@ -16,6 +17,23 @@ int main(int, char**) { | |||
16 | // We need to be able to create endpoints with full perms. | 17 | // We need to be able to create endpoints with full perms. |
17 | umask(0000); | 18 | umask(0000); |
18 | 19 | ||
20 | // Bump up the soft limit of open fd to the hard limit. | ||
21 | struct rlimit64 rlim; | ||
22 | ret = getrlimit64(RLIMIT_NOFILE, &rlim); | ||
23 | LOG_ALWAYS_FATAL_IF(ret != 0, "Failed to get nofile limit."); | ||
24 | |||
25 | ALOGI("Current nofile limit is %llu/%llu.", rlim.rlim_cur, rlim.rlim_max); | ||
26 | rlim.rlim_cur = rlim.rlim_max; | ||
27 | ret = setrlimit64(RLIMIT_NOFILE, &rlim); | ||
28 | ALOGE_IF(ret < 0, "Failed to set nofile limit, error=%s", strerror(errno)); | ||
29 | |||
30 | rlim.rlim_cur = -1; | ||
31 | rlim.rlim_max = -1; | ||
32 | if (getrlimit64(RLIMIT_NOFILE, &rlim) < 0) | ||
33 | ALOGE("Failed to get nofile limit."); | ||
34 | else | ||
35 | ALOGI("New nofile limit is %llu/%llu.", rlim.rlim_cur, rlim.rlim_max); | ||
36 | |||
19 | dispatcher = android::pdx::ServiceDispatcher::Create(); | 37 | dispatcher = android::pdx::ServiceDispatcher::Create(); |
20 | CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher\n"); | 38 | CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher\n"); |
21 | 39 | ||
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp index ac6896ae8..a6d2dbb60 100644 --- a/services/vr/bufferhubd/consumer_channel.cpp +++ b/services/vr/bufferhubd/consumer_channel.cpp | |||
@@ -19,9 +19,10 @@ namespace android { | |||
19 | namespace dvr { | 19 | namespace dvr { |
20 | 20 | ||
21 | ConsumerChannel::ConsumerChannel(BufferHubService* service, int buffer_id, | 21 | ConsumerChannel::ConsumerChannel(BufferHubService* service, int buffer_id, |
22 | int channel_id, | 22 | int channel_id, uint64_t consumer_state_bit, |
23 | const std::shared_ptr<Channel> producer) | 23 | const std::shared_ptr<Channel> producer) |
24 | : BufferHubChannel(service, buffer_id, channel_id, kConsumerType), | 24 | : BufferHubChannel(service, buffer_id, channel_id, kConsumerType), |
25 | consumer_state_bit_(consumer_state_bit), | ||
25 | producer_(producer) { | 26 | producer_(producer) { |
26 | GetProducer()->AddConsumer(this); | 27 | GetProducer()->AddConsumer(this); |
27 | } | 28 | } |
@@ -32,8 +33,6 @@ ConsumerChannel::~ConsumerChannel() { | |||
32 | channel_id(), buffer_id()); | 33 | channel_id(), buffer_id()); |
33 | 34 | ||
34 | if (auto producer = GetProducer()) { | 35 | if (auto producer = GetProducer()) { |
35 | if (!released_) // Producer is waiting for our Release. | ||
36 | producer->OnConsumerIgnored(); | ||
37 | producer->RemoveConsumer(this); | 36 | producer->RemoveConsumer(this); |
38 | } | 37 | } |
39 | } | 38 | } |
@@ -43,6 +42,8 @@ BufferHubChannel::BufferInfo ConsumerChannel::GetBufferInfo() const { | |||
43 | if (auto producer = GetProducer()) { | 42 | if (auto producer = GetProducer()) { |
44 | // If producer has not hung up, copy most buffer info from the producer. | 43 | // If producer has not hung up, copy most buffer info from the producer. |
45 | info = producer->GetBufferInfo(); | 44 | info = producer->GetBufferInfo(); |
45 | } else { | ||
46 | info.signaled_mask = consumer_state_bit(); | ||
46 | } | 47 | } |
47 | info.id = buffer_id(); | 48 | info.id = buffer_id(); |
48 | return info; | 49 | return info; |
@@ -55,6 +56,9 @@ std::shared_ptr<ProducerChannel> ConsumerChannel::GetProducer() const { | |||
55 | void ConsumerChannel::HandleImpulse(Message& message) { | 56 | void ConsumerChannel::HandleImpulse(Message& message) { |
56 | ATRACE_NAME("ConsumerChannel::HandleImpulse"); | 57 | ATRACE_NAME("ConsumerChannel::HandleImpulse"); |
57 | switch (message.GetOp()) { | 58 | switch (message.GetOp()) { |
59 | case BufferHubRPC::ConsumerAcquire::Opcode: | ||
60 | OnConsumerAcquire(message); | ||
61 | break; | ||
58 | case BufferHubRPC::ConsumerRelease::Opcode: | 62 | case BufferHubRPC::ConsumerRelease::Opcode: |
59 | OnConsumerRelease(message, {}); | 63 | OnConsumerRelease(message, {}); |
60 | break; | 64 | break; |
@@ -70,7 +74,7 @@ bool ConsumerChannel::HandleMessage(Message& message) { | |||
70 | switch (message.GetOp()) { | 74 | switch (message.GetOp()) { |
71 | case BufferHubRPC::GetBuffer::Opcode: | 75 | case BufferHubRPC::GetBuffer::Opcode: |
72 | DispatchRemoteMethod<BufferHubRPC::GetBuffer>( | 76 | DispatchRemoteMethod<BufferHubRPC::GetBuffer>( |
73 | *producer, &ProducerChannel::OnGetBuffer, message); | 77 | *this, &ConsumerChannel::OnGetBuffer, message); |
74 | return true; | 78 | return true; |
75 | 79 | ||
76 | case BufferHubRPC::NewConsumer::Opcode: | 80 | case BufferHubRPC::NewConsumer::Opcode: |
@@ -98,9 +102,18 @@ bool ConsumerChannel::HandleMessage(Message& message) { | |||
98 | } | 102 | } |
99 | } | 103 | } |
100 | 104 | ||
101 | Status<std::pair<BorrowedFence, ConsumerChannel::MetaData>> | 105 | Status<BufferDescription<BorrowedHandle>> ConsumerChannel::OnGetBuffer( |
102 | ConsumerChannel::OnConsumerAcquire(Message& message, | 106 | Message& /*message*/) { |
103 | std::size_t metadata_size) { | 107 | ATRACE_NAME("ConsumerChannel::OnGetBuffer"); |
108 | ALOGD_IF(TRACE, "ConsumerChannel::OnGetBuffer: buffer=%d", buffer_id()); | ||
109 | if (auto producer = GetProducer()) { | ||
110 | return {producer->GetBuffer(consumer_state_bit_)}; | ||
111 | } else { | ||
112 | return ErrorStatus(EPIPE); | ||
113 | } | ||
114 | } | ||
115 | |||
116 | Status<LocalFence> ConsumerChannel::OnConsumerAcquire(Message& message) { | ||
104 | ATRACE_NAME("ConsumerChannel::OnConsumerAcquire"); | 117 | ATRACE_NAME("ConsumerChannel::OnConsumerAcquire"); |
105 | auto producer = GetProducer(); | 118 | auto producer = GetProducer(); |
106 | if (!producer) | 119 | if (!producer) |
@@ -114,7 +127,7 @@ ConsumerChannel::OnConsumerAcquire(Message& message, | |||
114 | producer->buffer_id()); | 127 | producer->buffer_id()); |
115 | return ErrorStatus(EBUSY); | 128 | return ErrorStatus(EBUSY); |
116 | } else { | 129 | } else { |
117 | auto status = producer->OnConsumerAcquire(message, metadata_size); | 130 | auto status = producer->OnConsumerAcquire(message); |
118 | if (status) { | 131 | if (status) { |
119 | ClearAvailable(); | 132 | ClearAvailable(); |
120 | acquired_ = true; | 133 | acquired_ = true; |
diff --git a/services/vr/bufferhubd/consumer_channel.h b/services/vr/bufferhubd/consumer_channel.h index 208a00227..55cf96920 100644 --- a/services/vr/bufferhubd/consumer_channel.h +++ b/services/vr/bufferhubd/consumer_channel.h | |||
@@ -12,32 +12,35 @@ namespace dvr { | |||
12 | // Consumer channels are attached to a Producer channel | 12 | // Consumer channels are attached to a Producer channel |
13 | class ConsumerChannel : public BufferHubChannel { | 13 | class ConsumerChannel : public BufferHubChannel { |
14 | public: | 14 | public: |
15 | using BorrowedHandle = pdx::BorrowedHandle; | ||
15 | using Channel = pdx::Channel; | 16 | using Channel = pdx::Channel; |
16 | using Message = pdx::Message; | 17 | using Message = pdx::Message; |
17 | 18 | ||
18 | ConsumerChannel(BufferHubService* service, int buffer_id, int channel_id, | 19 | ConsumerChannel(BufferHubService* service, int buffer_id, int channel_id, |
20 | uint64_t consumer_state_bit, | ||
19 | const std::shared_ptr<Channel> producer); | 21 | const std::shared_ptr<Channel> producer); |
20 | ~ConsumerChannel() override; | 22 | ~ConsumerChannel() override; |
21 | 23 | ||
22 | bool HandleMessage(Message& message) override; | 24 | bool HandleMessage(Message& message) override; |
23 | void HandleImpulse(Message& message) override; | 25 | void HandleImpulse(Message& message) override; |
24 | 26 | ||
27 | uint64_t consumer_state_bit() const { return consumer_state_bit_; } | ||
25 | BufferInfo GetBufferInfo() const override; | 28 | BufferInfo GetBufferInfo() const override; |
26 | 29 | ||
27 | bool OnProducerPosted(); | 30 | bool OnProducerPosted(); |
28 | void OnProducerClosed(); | 31 | void OnProducerClosed(); |
29 | 32 | ||
30 | private: | 33 | private: |
31 | using MetaData = pdx::rpc::BufferWrapper<std::uint8_t*>; | ||
32 | |||
33 | std::shared_ptr<ProducerChannel> GetProducer() const; | 34 | std::shared_ptr<ProducerChannel> GetProducer() const; |
34 | 35 | ||
35 | pdx::Status<std::pair<BorrowedFence, MetaData>> OnConsumerAcquire( | 36 | pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message); |
36 | Message& message, std::size_t metadata_size); | 37 | |
38 | pdx::Status<LocalFence> OnConsumerAcquire(Message& message); | ||
37 | pdx::Status<void> OnConsumerRelease(Message& message, | 39 | pdx::Status<void> OnConsumerRelease(Message& message, |
38 | LocalFence release_fence); | 40 | LocalFence release_fence); |
39 | pdx::Status<void> OnConsumerSetIgnore(Message& message, bool ignore); | 41 | pdx::Status<void> OnConsumerSetIgnore(Message& message, bool ignore); |
40 | 42 | ||
43 | uint64_t consumer_state_bit_{0}; | ||
41 | bool acquired_{false}; | 44 | bool acquired_{false}; |
42 | bool released_{true}; | 45 | bool released_{true}; |
43 | bool ignored_{false}; // True if we are ignoring events. | 46 | bool ignored_{false}; // True if we are ignoring events. |
diff --git a/services/vr/bufferhubd/consumer_queue_channel.cpp b/services/vr/bufferhubd/consumer_queue_channel.cpp index f447e00c3..4d430012f 100644 --- a/services/vr/bufferhubd/consumer_queue_channel.cpp +++ b/services/vr/bufferhubd/consumer_queue_channel.cpp | |||
@@ -15,10 +15,11 @@ namespace dvr { | |||
15 | 15 | ||
16 | ConsumerQueueChannel::ConsumerQueueChannel( | 16 | ConsumerQueueChannel::ConsumerQueueChannel( |
17 | BufferHubService* service, int buffer_id, int channel_id, | 17 | BufferHubService* service, int buffer_id, int channel_id, |
18 | const std::shared_ptr<Channel>& producer) | 18 | const std::shared_ptr<Channel>& producer, bool silent) |
19 | : BufferHubChannel(service, buffer_id, channel_id, kConsumerQueueType), | 19 | : BufferHubChannel(service, buffer_id, channel_id, kConsumerQueueType), |
20 | producer_(producer), | 20 | producer_(producer), |
21 | capacity_(0) { | 21 | capacity_(0), |
22 | silent_(silent) { | ||
22 | GetProducer()->AddConsumer(this); | 23 | GetProducer()->AddConsumer(this); |
23 | } | 24 | } |
24 | 25 | ||
@@ -83,23 +84,30 @@ BufferHubChannel::BufferInfo ConsumerQueueChannel::GetBufferInfo() const { | |||
83 | void ConsumerQueueChannel::RegisterNewBuffer( | 84 | void ConsumerQueueChannel::RegisterNewBuffer( |
84 | const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot) { | 85 | const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot) { |
85 | ALOGD_IF(TRACE, | 86 | ALOGD_IF(TRACE, |
86 | "ConsumerQueueChannel::RegisterNewBuffer: buffer_id=%d slot=%zu", | 87 | "ConsumerQueueChannel::RegisterNewBuffer: queue_id=%d buffer_id=%d " |
87 | producer_channel->buffer_id(), slot); | 88 | "slot=%zu silent=%d", |
88 | pending_buffer_slots_.emplace(producer_channel, slot); | 89 | buffer_id(), producer_channel->buffer_id(), slot, silent_); |
89 | 90 | // Only register buffers if the queue is not silent. | |
90 | // Signal the client that there is new buffer available throught POLLIN. | 91 | if (!silent_) { |
91 | SignalAvailable(); | 92 | pending_buffer_slots_.emplace(producer_channel, slot); |
93 | |||
94 | // Signal the client that there is new buffer available. | ||
95 | SignalAvailable(); | ||
96 | } | ||
92 | } | 97 | } |
93 | 98 | ||
94 | Status<std::vector<std::pair<RemoteChannelHandle, size_t>>> | 99 | Status<std::vector<std::pair<RemoteChannelHandle, size_t>>> |
95 | ConsumerQueueChannel::OnConsumerQueueImportBuffers(Message& message) { | 100 | ConsumerQueueChannel::OnConsumerQueueImportBuffers(Message& message) { |
96 | std::vector<std::pair<RemoteChannelHandle, size_t>> buffer_handles; | 101 | std::vector<std::pair<RemoteChannelHandle, size_t>> buffer_handles; |
97 | ATRACE_NAME("ConsumerQueueChannel::OnConsumerQueueImportBuffers"); | 102 | ATRACE_NAME("ConsumerQueueChannel::OnConsumerQueueImportBuffers"); |
98 | ALOGD_IF( | 103 | ALOGD_IF(TRACE, |
99 | TRACE, | 104 | "ConsumerQueueChannel::OnConsumerQueueImportBuffers: " |
100 | "ConsumerQueueChannel::OnConsumerQueueImportBuffers number of buffers to " | 105 | "pending_buffer_slots=%zu", |
101 | "import: %zu", | 106 | pending_buffer_slots_.size()); |
102 | pending_buffer_slots_.size()); | 107 | |
108 | // Indicate this is a silent queue that will not import buffers. | ||
109 | if (silent_) | ||
110 | return ErrorStatus(EBADR); | ||
103 | 111 | ||
104 | while (!pending_buffer_slots_.empty()) { | 112 | while (!pending_buffer_slots_.empty()) { |
105 | auto producer_channel = pending_buffer_slots_.front().first.lock(); | 113 | auto producer_channel = pending_buffer_slots_.front().first.lock(); |
diff --git a/services/vr/bufferhubd/consumer_queue_channel.h b/services/vr/bufferhubd/consumer_queue_channel.h index aa3f531c7..8437c4cd0 100644 --- a/services/vr/bufferhubd/consumer_queue_channel.h +++ b/services/vr/bufferhubd/consumer_queue_channel.h | |||
@@ -19,7 +19,7 @@ class ConsumerQueueChannel : public BufferHubChannel { | |||
19 | using RemoteChannelHandle = pdx::RemoteChannelHandle; | 19 | using RemoteChannelHandle = pdx::RemoteChannelHandle; |
20 | 20 | ||
21 | ConsumerQueueChannel(BufferHubService* service, int buffer_id, int channel_id, | 21 | ConsumerQueueChannel(BufferHubService* service, int buffer_id, int channel_id, |
22 | const std::shared_ptr<Channel>& producer); | 22 | const std::shared_ptr<Channel>& producer, bool silent); |
23 | ~ConsumerQueueChannel() override; | 23 | ~ConsumerQueueChannel() override; |
24 | 24 | ||
25 | bool HandleMessage(Message& message) override; | 25 | bool HandleMessage(Message& message) override; |
@@ -54,6 +54,10 @@ class ConsumerQueueChannel : public BufferHubChannel { | |||
54 | // Tracks how many buffers have this queue imported. | 54 | // Tracks how many buffers have this queue imported. |
55 | size_t capacity_; | 55 | size_t capacity_; |
56 | 56 | ||
57 | // A silent queue does not signal or export buffers. It is only used to spawn | ||
58 | // another consumer queue. | ||
59 | bool silent_; | ||
60 | |||
57 | ConsumerQueueChannel(const ConsumerQueueChannel&) = delete; | 61 | ConsumerQueueChannel(const ConsumerQueueChannel&) = delete; |
58 | void operator=(const ConsumerQueueChannel&) = delete; | 62 | void operator=(const ConsumerQueueChannel&) = delete; |
59 | }; | 63 | }; |
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp index b2db79571..716db5eea 100644 --- a/services/vr/bufferhubd/producer_channel.cpp +++ b/services/vr/bufferhubd/producer_channel.cpp | |||
@@ -2,6 +2,8 @@ | |||
2 | 2 | ||
3 | #include <log/log.h> | 3 | #include <log/log.h> |
4 | #include <sync/sync.h> | 4 | #include <sync/sync.h> |
5 | #include <sys/epoll.h> | ||
6 | #include <sys/eventfd.h> | ||
5 | #include <sys/poll.h> | 7 | #include <sys/poll.h> |
6 | #include <utils/Trace.h> | 8 | #include <utils/Trace.h> |
7 | 9 | ||
@@ -24,24 +26,88 @@ using android::pdx::rpc::WrapBuffer; | |||
24 | namespace android { | 26 | namespace android { |
25 | namespace dvr { | 27 | namespace dvr { |
26 | 28 | ||
29 | namespace { | ||
30 | |||
31 | static inline uint64_t FindNextClearedBit(uint64_t bits) { | ||
32 | return ~bits - (~bits & (~bits - 1)); | ||
33 | } | ||
34 | |||
35 | } // namespace | ||
36 | |||
27 | ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id, | 37 | ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id, |
28 | uint32_t width, uint32_t height, | 38 | uint32_t width, uint32_t height, |
29 | uint32_t layer_count, uint32_t format, | 39 | uint32_t layer_count, uint32_t format, |
30 | uint64_t usage, size_t meta_size_bytes, | 40 | uint64_t usage, size_t user_metadata_size, |
31 | int* error) | 41 | int* error) |
32 | : BufferHubChannel(service, channel_id, channel_id, kProducerType), | 42 | : BufferHubChannel(service, channel_id, channel_id, kProducerType), |
33 | pending_consumers_(0), | 43 | pending_consumers_(0), |
34 | producer_owns_(true), | 44 | producer_owns_(true), |
35 | meta_size_bytes_(meta_size_bytes), | 45 | user_metadata_size_(user_metadata_size), |
36 | meta_(meta_size_bytes ? new uint8_t[meta_size_bytes] : nullptr) { | 46 | metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize + |
37 | const int ret = buffer_.Alloc(width, height, layer_count, format, usage); | 47 | user_metadata_size) { |
38 | if (ret < 0) { | 48 | if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) { |
39 | ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s", | 49 | ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s", |
40 | strerror(-ret)); | 50 | strerror(-ret)); |
41 | *error = ret; | 51 | *error = ret; |
42 | return; | 52 | return; |
43 | } | 53 | } |
44 | 54 | ||
55 | if (int ret = metadata_buffer_.Alloc(metadata_buf_size_, /*height=*/1, | ||
56 | /*layer_count=*/1, | ||
57 | BufferHubDefs::kMetadataFormat, | ||
58 | BufferHubDefs::kMetadataUsage)) { | ||
59 | ALOGE("ProducerChannel::ProducerChannel: Failed to allocate metadata: %s", | ||
60 | strerror(-ret)); | ||
61 | *error = ret; | ||
62 | return; | ||
63 | } | ||
64 | |||
65 | void* metadata_ptr = nullptr; | ||
66 | if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0, | ||
67 | /*y=*/0, metadata_buf_size_, | ||
68 | /*height=*/1, &metadata_ptr)) { | ||
69 | ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata."); | ||
70 | *error = -ret; | ||
71 | return; | ||
72 | } | ||
73 | metadata_header_ = | ||
74 | reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr); | ||
75 | |||
76 | // Using placement new here to reuse shared memory instead of new allocation | ||
77 | // and also initialize the value to zero. | ||
78 | buffer_state_ = | ||
79 | new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0); | ||
80 | fence_state_ = | ||
81 | new (&metadata_header_->fence_state) std::atomic<uint64_t>(0); | ||
82 | |||
83 | acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC)); | ||
84 | release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC)); | ||
85 | if (!acquire_fence_fd_ || !release_fence_fd_) { | ||
86 | ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences."); | ||
87 | *error = -EIO; | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); | ||
92 | if (!dummy_fence_fd_) { | ||
93 | ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences."); | ||
94 | *error = -EIO; | ||
95 | return; | ||
96 | } | ||
97 | |||
98 | epoll_event event; | ||
99 | event.events = 0; | ||
100 | event.data.u64 = 0ULL; | ||
101 | if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(), | ||
102 | &event) < 0) { | ||
103 | ALOGE( | ||
104 | "ProducerChannel::ProducerChannel: Failed to modify the shared " | ||
105 | "release fence to include the dummy fence: %s", | ||
106 | strerror(errno)); | ||
107 | *error = -EIO; | ||
108 | return; | ||
109 | } | ||
110 | |||
45 | // Success. | 111 | // Success. |
46 | *error = 0; | 112 | *error = 0; |
47 | } | 113 | } |
@@ -49,11 +115,11 @@ ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id, | |||
49 | Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create( | 115 | Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create( |
50 | BufferHubService* service, int channel_id, uint32_t width, uint32_t height, | 116 | BufferHubService* service, int channel_id, uint32_t width, uint32_t height, |
51 | uint32_t layer_count, uint32_t format, uint64_t usage, | 117 | uint32_t layer_count, uint32_t format, uint64_t usage, |
52 | size_t meta_size_bytes) { | 118 | size_t user_metadata_size) { |
53 | int error; | 119 | int error; |
54 | std::shared_ptr<ProducerChannel> producer( | 120 | std::shared_ptr<ProducerChannel> producer( |
55 | new ProducerChannel(service, channel_id, width, height, layer_count, | 121 | new ProducerChannel(service, channel_id, width, height, layer_count, |
56 | format, usage, meta_size_bytes, &error)); | 122 | format, usage, user_metadata_size, &error)); |
57 | if (error < 0) | 123 | if (error < 0) |
58 | return ErrorStatus(-error); | 124 | return ErrorStatus(-error); |
59 | else | 125 | else |
@@ -62,16 +128,24 @@ Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create( | |||
62 | 128 | ||
63 | ProducerChannel::~ProducerChannel() { | 129 | ProducerChannel::~ProducerChannel() { |
64 | ALOGD_IF(TRACE, | 130 | ALOGD_IF(TRACE, |
65 | "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d", | 131 | "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d " |
66 | channel_id(), buffer_id()); | 132 | "state=%" PRIx64 ".", |
133 | channel_id(), buffer_id(), buffer_state_->load()); | ||
67 | for (auto consumer : consumer_channels_) | 134 | for (auto consumer : consumer_channels_) |
68 | consumer->OnProducerClosed(); | 135 | consumer->OnProducerClosed(); |
69 | } | 136 | } |
70 | 137 | ||
71 | BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const { | 138 | BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const { |
139 | // Derive the mask of signaled buffers in this producer / consumer set. | ||
140 | uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0; | ||
141 | for (const ConsumerChannel* consumer : consumer_channels_) { | ||
142 | signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0; | ||
143 | } | ||
144 | |||
72 | return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(), | 145 | return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(), |
73 | buffer_.height(), buffer_.layer_count(), buffer_.format(), | 146 | buffer_.height(), buffer_.layer_count(), buffer_.format(), |
74 | buffer_.usage(), name_); | 147 | buffer_.usage(), pending_consumers_, buffer_state_->load(), |
148 | signaled_mask, metadata_header_->queue_index, name_); | ||
75 | } | 149 | } |
76 | 150 | ||
77 | void ProducerChannel::HandleImpulse(Message& message) { | 151 | void ProducerChannel::HandleImpulse(Message& message) { |
@@ -80,6 +154,9 @@ void ProducerChannel::HandleImpulse(Message& message) { | |||
80 | case BufferHubRPC::ProducerGain::Opcode: | 154 | case BufferHubRPC::ProducerGain::Opcode: |
81 | OnProducerGain(message); | 155 | OnProducerGain(message); |
82 | break; | 156 | break; |
157 | case BufferHubRPC::ProducerPost::Opcode: | ||
158 | OnProducerPost(message, {}); | ||
159 | break; | ||
83 | } | 160 | } |
84 | } | 161 | } |
85 | 162 | ||
@@ -121,16 +198,26 @@ bool ProducerChannel::HandleMessage(Message& message) { | |||
121 | } | 198 | } |
122 | } | 199 | } |
123 | 200 | ||
124 | Status<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffer( | 201 | BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer( |
202 | uint64_t buffer_state_bit) { | ||
203 | return { | ||
204 | buffer_, metadata_buffer_, buffer_id(), | ||
205 | buffer_state_bit, acquire_fence_fd_.Borrow(), release_fence_fd_.Borrow()}; | ||
206 | } | ||
207 | |||
208 | Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer( | ||
125 | Message& /*message*/) { | 209 | Message& /*message*/) { |
126 | ATRACE_NAME("ProducerChannel::OnGetBuffer"); | 210 | ATRACE_NAME("ProducerChannel::OnGetBuffer"); |
127 | ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id()); | 211 | ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".", |
128 | return {NativeBufferHandle<BorrowedHandle>(buffer_, buffer_id())}; | 212 | buffer_id(), buffer_state_->load()); |
213 | return {GetBuffer(BufferHubDefs::kProducerStateBit)}; | ||
129 | } | 214 | } |
130 | 215 | ||
131 | Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) { | 216 | Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) { |
132 | ATRACE_NAME("ProducerChannel::CreateConsumer"); | 217 | ATRACE_NAME("ProducerChannel::CreateConsumer"); |
133 | ALOGD_IF(TRACE, "ProducerChannel::CreateConsumer: buffer_id=%d", buffer_id()); | 218 | ALOGD_IF(TRACE, |
219 | "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d", | ||
220 | buffer_id(), producer_owns_); | ||
134 | 221 | ||
135 | int channel_id; | 222 | int channel_id; |
136 | auto status = message.PushChannel(0, nullptr, &channel_id); | 223 | auto status = message.PushChannel(0, nullptr, &channel_id); |
@@ -141,8 +228,21 @@ Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) { | |||
141 | return ErrorStatus(ENOMEM); | 228 | return ErrorStatus(ENOMEM); |
142 | } | 229 | } |
143 | 230 | ||
144 | auto consumer = std::make_shared<ConsumerChannel>( | 231 | // Try find the next consumer state bit which has not been claimed by any |
145 | service(), buffer_id(), channel_id, shared_from_this()); | 232 | // consumer yet. |
233 | uint64_t consumer_state_bit = FindNextClearedBit( | ||
234 | active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ | | ||
235 | BufferHubDefs::kProducerStateBit); | ||
236 | if (consumer_state_bit == 0ULL) { | ||
237 | ALOGE( | ||
238 | "ProducerChannel::CreateConsumer: reached the maximum mumber of " | ||
239 | "consumers per producer: 63."); | ||
240 | return ErrorStatus(E2BIG); | ||
241 | } | ||
242 | |||
243 | auto consumer = | ||
244 | std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id, | ||
245 | consumer_state_bit, shared_from_this()); | ||
146 | const auto channel_status = service()->SetChannel(channel_id, consumer); | 246 | const auto channel_status = service()->SetChannel(channel_id, consumer); |
147 | if (!channel_status) { | 247 | if (!channel_status) { |
148 | ALOGE( | 248 | ALOGE( |
@@ -152,12 +252,14 @@ Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) { | |||
152 | return ErrorStatus(ENOMEM); | 252 | return ErrorStatus(ENOMEM); |
153 | } | 253 | } |
154 | 254 | ||
155 | if (!producer_owns_) { | 255 | if (!producer_owns_ && |
256 | !BufferHubDefs::IsBufferReleased(buffer_state_->load())) { | ||
156 | // Signal the new consumer when adding it to a posted producer. | 257 | // Signal the new consumer when adding it to a posted producer. |
157 | if (consumer->OnProducerPosted()) | 258 | if (consumer->OnProducerPosted()) |
158 | pending_consumers_++; | 259 | pending_consumers_++; |
159 | } | 260 | } |
160 | 261 | ||
262 | active_consumer_bit_mask_ |= consumer_state_bit; | ||
161 | return {status.take()}; | 263 | return {status.take()}; |
162 | } | 264 | } |
163 | 265 | ||
@@ -168,8 +270,7 @@ Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) { | |||
168 | } | 270 | } |
169 | 271 | ||
170 | Status<void> ProducerChannel::OnProducerPost( | 272 | Status<void> ProducerChannel::OnProducerPost( |
171 | Message&, LocalFence acquire_fence, | 273 | Message&, LocalFence acquire_fence) { |
172 | BufferWrapper<std::vector<std::uint8_t>> metadata) { | ||
173 | ATRACE_NAME("ProducerChannel::OnProducerPost"); | 274 | ATRACE_NAME("ProducerChannel::OnProducerPost"); |
174 | ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id()); | 275 | ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id()); |
175 | if (!producer_owns_) { | 276 | if (!producer_owns_) { |
@@ -177,27 +278,45 @@ Status<void> ProducerChannel::OnProducerPost( | |||
177 | return ErrorStatus(EBUSY); | 278 | return ErrorStatus(EBUSY); |
178 | } | 279 | } |
179 | 280 | ||
180 | if (meta_size_bytes_ != metadata.size()) { | 281 | epoll_event event; |
181 | ALOGD_IF(TRACE, | 282 | event.events = 0; |
182 | "ProducerChannel::OnProducerPost: Expected meta_size_bytes=%zu " | 283 | event.data.u64 = 0ULL; |
183 | "got size=%zu", | 284 | int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD, |
184 | meta_size_bytes_, metadata.size()); | 285 | dummy_fence_fd_.Get(), &event); |
185 | return ErrorStatus(EINVAL); | 286 | ALOGE_IF(ret < 0, |
287 | "ProducerChannel::OnProducerPost: Failed to modify the shared " | ||
288 | "release fence to include the dummy fence: %s", | ||
289 | strerror(errno)); | ||
290 | |||
291 | eventfd_t dummy_fence_count = 0ULL; | ||
292 | if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) { | ||
293 | const int error = errno; | ||
294 | if (error != EAGAIN) { | ||
295 | ALOGE( | ||
296 | "ProducerChannel::ProducerChannel: Failed to read dummy fence, " | ||
297 | "error: %s", | ||
298 | strerror(error)); | ||
299 | return ErrorStatus(error); | ||
300 | } | ||
186 | } | 301 | } |
187 | 302 | ||
188 | std::copy(metadata.begin(), metadata.end(), meta_.get()); | 303 | ALOGW_IF(dummy_fence_count > 0, |
304 | "ProducerChannel::ProducerChannel: %" PRIu64 | ||
305 | " dummy fence(s) was signaled during last release/gain cycle " | ||
306 | "buffer_id=%d.", | ||
307 | dummy_fence_count, buffer_id()); | ||
308 | |||
189 | post_fence_ = std::move(acquire_fence); | 309 | post_fence_ = std::move(acquire_fence); |
190 | producer_owns_ = false; | 310 | producer_owns_ = false; |
191 | 311 | ||
192 | // Signal any interested consumers. If there are none, automatically release | 312 | // Signal any interested consumers. If there are none, the buffer will stay |
193 | // the buffer. | 313 | // in posted state until a consumer comes online. This behavior guarantees |
314 | // that no frame is silently dropped. | ||
194 | pending_consumers_ = 0; | 315 | pending_consumers_ = 0; |
195 | for (auto consumer : consumer_channels_) { | 316 | for (auto consumer : consumer_channels_) { |
196 | if (consumer->OnProducerPosted()) | 317 | if (consumer->OnProducerPosted()) |
197 | pending_consumers_++; | 318 | pending_consumers_++; |
198 | } | 319 | } |
199 | if (pending_consumers_ == 0) | ||
200 | SignalAvailable(); | ||
201 | ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers", | 320 | ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers", |
202 | pending_consumers_); | 321 | pending_consumers_); |
203 | 322 | ||
@@ -214,8 +333,13 @@ Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) { | |||
214 | } | 333 | } |
215 | 334 | ||
216 | // There are still pending consumers, return busy. | 335 | // There are still pending consumers, return busy. |
217 | if (pending_consumers_ > 0) | 336 | if (pending_consumers_ > 0) { |
337 | ALOGE( | ||
338 | "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that " | ||
339 | "still has %d pending consumer(s).", | ||
340 | buffer_id(), pending_consumers_); | ||
218 | return ErrorStatus(EBUSY); | 341 | return ErrorStatus(EBUSY); |
342 | } | ||
219 | 343 | ||
220 | ClearAvailable(); | 344 | ClearAvailable(); |
221 | producer_owns_ = true; | 345 | producer_owns_ = true; |
@@ -223,9 +347,7 @@ Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) { | |||
223 | return {std::move(returned_fence_)}; | 347 | return {std::move(returned_fence_)}; |
224 | } | 348 | } |
225 | 349 | ||
226 | Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>> | 350 | Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) { |
227 | ProducerChannel::OnConsumerAcquire(Message& /*message*/, | ||
228 | std::size_t metadata_size) { | ||
229 | ATRACE_NAME("ProducerChannel::OnConsumerAcquire"); | 351 | ATRACE_NAME("ProducerChannel::OnConsumerAcquire"); |
230 | ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d", | 352 | ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d", |
231 | buffer_id()); | 353 | buffer_id()); |
@@ -236,12 +358,7 @@ ProducerChannel::OnConsumerAcquire(Message& /*message*/, | |||
236 | 358 | ||
237 | // Return a borrowed fd to avoid unnecessary duplication of the underlying fd. | 359 | // Return a borrowed fd to avoid unnecessary duplication of the underlying fd. |
238 | // Serialization just needs to read the handle. | 360 | // Serialization just needs to read the handle. |
239 | if (metadata_size == 0) | 361 | return {std::move(post_fence_)}; |
240 | return {std::make_pair(post_fence_.borrow(), | ||
241 | WrapBuffer<std::uint8_t>(nullptr, 0))}; | ||
242 | else | ||
243 | return {std::make_pair(post_fence_.borrow(), | ||
244 | WrapBuffer(meta_.get(), meta_size_bytes_))}; | ||
245 | } | 362 | } |
246 | 363 | ||
247 | Status<void> ProducerChannel::OnConsumerRelease(Message&, | 364 | Status<void> ProducerChannel::OnConsumerRelease(Message&, |
@@ -273,17 +390,75 @@ Status<void> ProducerChannel::OnConsumerRelease(Message&, | |||
273 | } | 390 | } |
274 | 391 | ||
275 | OnConsumerIgnored(); | 392 | OnConsumerIgnored(); |
393 | if (pending_consumers_ == 0) { | ||
394 | // Clear the producer bit atomically to transit into released state. This | ||
395 | // has to done by BufferHub as it requries synchronization among all | ||
396 | // consumers. | ||
397 | BufferHubDefs::ModifyBufferState(buffer_state_, | ||
398 | BufferHubDefs::kProducerStateBit, 0ULL); | ||
399 | ALOGD_IF(TRACE, | ||
400 | "ProducerChannel::OnConsumerRelease: releasing last consumer: " | ||
401 | "buffer_id=%d state=%" PRIx64 ".", | ||
402 | buffer_id(), buffer_state_->load()); | ||
403 | |||
404 | if (orphaned_consumer_bit_mask_) { | ||
405 | ALOGW( | ||
406 | "ProducerChannel::OnConsumerRelease: orphaned buffer detected " | ||
407 | "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64 | ||
408 | " queue_index=%" PRIu64 ".", | ||
409 | buffer_id(), orphaned_consumer_bit_mask_, | ||
410 | metadata_header_->queue_index); | ||
411 | orphaned_consumer_bit_mask_ = 0; | ||
412 | } | ||
413 | |||
414 | SignalAvailable(); | ||
415 | } | ||
416 | |||
417 | ALOGE_IF(pending_consumers_ && | ||
418 | BufferHubDefs::IsBufferReleased(buffer_state_->load()), | ||
419 | "ProducerChannel::OnConsumerRelease: buffer state inconsistent: " | ||
420 | "pending_consumers=%d, buffer buffer is in releaed state.", | ||
421 | pending_consumers_); | ||
276 | return {}; | 422 | return {}; |
277 | } | 423 | } |
278 | 424 | ||
279 | void ProducerChannel::OnConsumerIgnored() { | 425 | void ProducerChannel::OnConsumerIgnored() { |
280 | if (!--pending_consumers_) | 426 | if (pending_consumers_ == 0) { |
281 | SignalAvailable(); | 427 | ALOGE("ProducerChannel::OnConsumerIgnored: no pending consumer."); |
428 | return; | ||
429 | } | ||
430 | |||
431 | --pending_consumers_; | ||
282 | ALOGD_IF(TRACE, | 432 | ALOGD_IF(TRACE, |
283 | "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left", | 433 | "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left", |
284 | buffer_id(), pending_consumers_); | 434 | buffer_id(), pending_consumers_); |
285 | } | 435 | } |
286 | 436 | ||
437 | void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) { | ||
438 | // Ignore the orphaned consumer. | ||
439 | OnConsumerIgnored(); | ||
440 | |||
441 | const uint64_t consumer_state_bit = channel->consumer_state_bit(); | ||
442 | ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit, | ||
443 | "ProducerChannel::OnConsumerOrphaned: Consumer " | ||
444 | "(consumer_state_bit=%" PRIx64 ") is already orphaned.", | ||
445 | consumer_state_bit); | ||
446 | orphaned_consumer_bit_mask_ |= consumer_state_bit; | ||
447 | |||
448 | // Atomically clear the fence state bit as an orphaned consumer will never | ||
449 | // signal a release fence. Also clear the buffer state as it won't be released | ||
450 | // as well. | ||
451 | fence_state_->fetch_and(~consumer_state_bit); | ||
452 | BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL); | ||
453 | |||
454 | ALOGW( | ||
455 | "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer " | ||
456 | "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64 | ||
457 | " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".", | ||
458 | buffer_id(), consumer_state_bit, metadata_header_->queue_index, | ||
459 | buffer_state_->load(), fence_state_->load()); | ||
460 | } | ||
461 | |||
287 | Status<void> ProducerChannel::OnProducerMakePersistent(Message& message, | 462 | Status<void> ProducerChannel::OnProducerMakePersistent(Message& message, |
288 | const std::string& name, | 463 | const std::string& name, |
289 | int user_id, | 464 | int user_id, |
@@ -335,6 +510,40 @@ void ProducerChannel::AddConsumer(ConsumerChannel* channel) { | |||
335 | void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) { | 510 | void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) { |
336 | consumer_channels_.erase( | 511 | consumer_channels_.erase( |
337 | std::find(consumer_channels_.begin(), consumer_channels_.end(), channel)); | 512 | std::find(consumer_channels_.begin(), consumer_channels_.end(), channel)); |
513 | active_consumer_bit_mask_ &= ~channel->consumer_state_bit(); | ||
514 | |||
515 | const uint64_t buffer_state = buffer_state_->load(); | ||
516 | if (BufferHubDefs::IsBufferPosted(buffer_state) || | ||
517 | BufferHubDefs::IsBufferAcquired(buffer_state)) { | ||
518 | // The consumer client is being destoryed without releasing. This could | ||
519 | // happen in corner cases when the consumer crashes. Here we mark it | ||
520 | // orphaned before remove it from producer. | ||
521 | OnConsumerOrphaned(channel); | ||
522 | } | ||
523 | |||
524 | if (BufferHubDefs::IsBufferReleased(buffer_state) || | ||
525 | BufferHubDefs::IsBufferGained(buffer_state)) { | ||
526 | // The consumer is being close while it is suppose to signal a release | ||
527 | // fence. Signal the dummy fence here. | ||
528 | if (fence_state_->load() & channel->consumer_state_bit()) { | ||
529 | epoll_event event; | ||
530 | event.events = EPOLLIN; | ||
531 | event.data.u64 = channel->consumer_state_bit(); | ||
532 | if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD, | ||
533 | dummy_fence_fd_.Get(), &event) < 0) { | ||
534 | ALOGE( | ||
535 | "ProducerChannel::RemoveConsumer: Failed to modify the shared " | ||
536 | "release fence to include the dummy fence: %s", | ||
537 | strerror(errno)); | ||
538 | return; | ||
539 | } | ||
540 | ALOGW( | ||
541 | "ProducerChannel::RemoveConsumer: signal dummy release fence " | ||
542 | "buffer_id=%d", | ||
543 | buffer_id()); | ||
544 | eventfd_write(dummy_fence_fd_.Get(), 1); | ||
545 | } | ||
546 | } | ||
338 | } | 547 | } |
339 | 548 | ||
340 | // Returns true if either the user or group ids match the owning ids or both | 549 | // Returns true if either the user or group ids match the owning ids or both |
@@ -350,10 +559,12 @@ bool ProducerChannel::CheckAccess(int euid, int egid) { | |||
350 | // Returns true if the given parameters match the underlying buffer parameters. | 559 | // Returns true if the given parameters match the underlying buffer parameters. |
351 | bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height, | 560 | bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height, |
352 | uint32_t layer_count, uint32_t format, | 561 | uint32_t layer_count, uint32_t format, |
353 | uint64_t usage, size_t meta_size_bytes) { | 562 | uint64_t usage, |
354 | return meta_size_bytes == meta_size_bytes_ && buffer_.width() == width && | 563 | size_t user_metadata_size) { |
355 | buffer_.height() == height && buffer_.layer_count() == layer_count && | 564 | return user_metadata_size == user_metadata_size_ && |
356 | buffer_.format() == format && buffer_.usage() == usage; | 565 | buffer_.width() == width && buffer_.height() == height && |
566 | buffer_.layer_count() == layer_count && buffer_.format() == format && | ||
567 | buffer_.usage() == usage; | ||
357 | } | 568 | } |
358 | 569 | ||
359 | } // namespace dvr | 570 | } // namespace dvr |
diff --git a/services/vr/bufferhubd/producer_channel.h b/services/vr/bufferhubd/producer_channel.h index 5ada47880..e280f4de8 100644 --- a/services/vr/bufferhubd/producer_channel.h +++ b/services/vr/bufferhubd/producer_channel.h | |||
@@ -33,7 +33,7 @@ class ProducerChannel : public BufferHubChannel { | |||
33 | static pdx::Status<std::shared_ptr<ProducerChannel>> Create( | 33 | static pdx::Status<std::shared_ptr<ProducerChannel>> Create( |
34 | BufferHubService* service, int channel_id, uint32_t width, | 34 | BufferHubService* service, int channel_id, uint32_t width, |
35 | uint32_t height, uint32_t layer_count, uint32_t format, uint64_t usage, | 35 | uint32_t height, uint32_t layer_count, uint32_t format, uint64_t usage, |
36 | size_t meta_size_bytes); | 36 | size_t user_metadata_size); |
37 | 37 | ||
38 | ~ProducerChannel() override; | 38 | ~ProducerChannel() override; |
39 | 39 | ||
@@ -42,24 +42,25 @@ class ProducerChannel : public BufferHubChannel { | |||
42 | 42 | ||
43 | BufferInfo GetBufferInfo() const override; | 43 | BufferInfo GetBufferInfo() const override; |
44 | 44 | ||
45 | pdx::Status<NativeBufferHandle<BorrowedHandle>> OnGetBuffer(Message& message); | 45 | BufferDescription<BorrowedHandle> GetBuffer(uint64_t buffer_state_bit); |
46 | 46 | ||
47 | pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message); | 47 | pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message); |
48 | pdx::Status<RemoteChannelHandle> OnNewConsumer(Message& message); | 48 | pdx::Status<RemoteChannelHandle> OnNewConsumer(Message& message); |
49 | 49 | ||
50 | pdx::Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>> | 50 | pdx::Status<LocalFence> OnConsumerAcquire(Message& message); |
51 | OnConsumerAcquire(Message& message, std::size_t metadata_size); | ||
52 | pdx::Status<void> OnConsumerRelease(Message& message, | 51 | pdx::Status<void> OnConsumerRelease(Message& message, |
53 | LocalFence release_fence); | 52 | LocalFence release_fence); |
54 | 53 | ||
55 | void OnConsumerIgnored(); | 54 | void OnConsumerIgnored(); |
55 | void OnConsumerOrphaned(ConsumerChannel* channel); | ||
56 | 56 | ||
57 | void AddConsumer(ConsumerChannel* channel); | 57 | void AddConsumer(ConsumerChannel* channel); |
58 | void RemoveConsumer(ConsumerChannel* channel); | 58 | void RemoveConsumer(ConsumerChannel* channel); |
59 | 59 | ||
60 | bool CheckAccess(int euid, int egid); | 60 | bool CheckAccess(int euid, int egid); |
61 | bool CheckParameters(uint32_t width, uint32_t height, uint32_t layer_count, | 61 | bool CheckParameters(uint32_t width, uint32_t height, uint32_t layer_count, |
62 | uint32_t format, uint64_t usage, size_t meta_size_bytes); | 62 | uint32_t format, uint64_t usage, |
63 | size_t user_metadata_size); | ||
63 | 64 | ||
64 | pdx::Status<void> OnProducerMakePersistent(Message& message, | 65 | pdx::Status<void> OnProducerMakePersistent(Message& message, |
65 | const std::string& name, | 66 | const std::string& name, |
@@ -74,11 +75,28 @@ class ProducerChannel : public BufferHubChannel { | |||
74 | 75 | ||
75 | IonBuffer buffer_; | 76 | IonBuffer buffer_; |
76 | 77 | ||
78 | // IonBuffer that is shared between bufferhubd, producer, and consumers. | ||
79 | IonBuffer metadata_buffer_; | ||
80 | BufferHubDefs::MetadataHeader* metadata_header_ = nullptr; | ||
81 | std::atomic<uint64_t>* buffer_state_ = nullptr; | ||
82 | std::atomic<uint64_t>* fence_state_ = nullptr; | ||
83 | |||
84 | // All active consumer bits. Valid bits are the lower 63 bits, while the | ||
85 | // highest bit is reserved for the producer and should not be set. | ||
86 | uint64_t active_consumer_bit_mask_{0ULL}; | ||
87 | // All orphaned consumer bits. Valid bits are the lower 63 bits, while the | ||
88 | // highest bit is reserved for the producer and should not be set. | ||
89 | uint64_t orphaned_consumer_bit_mask_{0ULL}; | ||
90 | |||
77 | bool producer_owns_; | 91 | bool producer_owns_; |
78 | LocalFence post_fence_; | 92 | LocalFence post_fence_; |
79 | LocalFence returned_fence_; | 93 | LocalFence returned_fence_; |
80 | size_t meta_size_bytes_; | 94 | size_t user_metadata_size_; // size of user requested buffer buffer size. |
81 | std::unique_ptr<uint8_t[]> meta_; | 95 | size_t metadata_buf_size_; // size of the ion buffer that holds metadata. |
96 | |||
97 | pdx::LocalHandle acquire_fence_fd_; | ||
98 | pdx::LocalHandle release_fence_fd_; | ||
99 | pdx::LocalHandle dummy_fence_fd_; | ||
82 | 100 | ||
83 | static constexpr int kNoCheckId = -1; | 101 | static constexpr int kNoCheckId = -1; |
84 | static constexpr int kUseCallerId = 0; | 102 | static constexpr int kUseCallerId = 0; |
@@ -92,11 +110,10 @@ class ProducerChannel : public BufferHubChannel { | |||
92 | 110 | ||
93 | ProducerChannel(BufferHubService* service, int channel, uint32_t width, | 111 | ProducerChannel(BufferHubService* service, int channel, uint32_t width, |
94 | uint32_t height, uint32_t layer_count, uint32_t format, | 112 | uint32_t height, uint32_t layer_count, uint32_t format, |
95 | uint64_t usage, size_t meta_size_bytes, int* error); | 113 | uint64_t usage, size_t user_metadata_size, int* error); |
96 | 114 | ||
97 | pdx::Status<void> OnProducerPost( | 115 | pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message); |
98 | Message& message, LocalFence acquire_fence, | 116 | pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence); |
99 | BufferWrapper<std::vector<std::uint8_t>> metadata); | ||
100 | pdx::Status<LocalFence> OnProducerGain(Message& message); | 117 | pdx::Status<LocalFence> OnProducerGain(Message& message); |
101 | 118 | ||
102 | ProducerChannel(const ProducerChannel&) = delete; | 119 | ProducerChannel(const ProducerChannel&) = delete; |
diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp index b8bb728b7..c0c48c2dc 100644 --- a/services/vr/bufferhubd/producer_queue_channel.cpp +++ b/services/vr/bufferhubd/producer_queue_channel.cpp | |||
@@ -7,8 +7,8 @@ | |||
7 | 7 | ||
8 | using android::pdx::ErrorStatus; | 8 | using android::pdx::ErrorStatus; |
9 | using android::pdx::Message; | 9 | using android::pdx::Message; |
10 | using android::pdx::Status; | ||
11 | using android::pdx::RemoteChannelHandle; | 10 | using android::pdx::RemoteChannelHandle; |
11 | using android::pdx::Status; | ||
12 | using android::pdx::rpc::DispatchRemoteMethod; | 12 | using android::pdx::rpc::DispatchRemoteMethod; |
13 | 13 | ||
14 | namespace android { | 14 | namespace android { |
@@ -96,10 +96,12 @@ BufferHubChannel::BufferInfo ProducerQueueChannel::GetBufferInfo() const { | |||
96 | } | 96 | } |
97 | 97 | ||
98 | Status<RemoteChannelHandle> ProducerQueueChannel::OnCreateConsumerQueue( | 98 | Status<RemoteChannelHandle> ProducerQueueChannel::OnCreateConsumerQueue( |
99 | Message& message) { | 99 | Message& message, bool silent) { |
100 | ATRACE_NAME("ProducerQueueChannel::OnCreateConsumerQueue"); | 100 | ATRACE_NAME("ProducerQueueChannel::OnCreateConsumerQueue"); |
101 | ALOGD_IF(TRACE, "ProducerQueueChannel::OnCreateConsumerQueue: channel_id=%d", | 101 | ALOGD_IF( |
102 | channel_id()); | 102 | TRACE, |
103 | "ProducerQueueChannel::OnCreateConsumerQueue: channel_id=%d slient=%d", | ||
104 | channel_id(), silent); | ||
103 | 105 | ||
104 | int channel_id; | 106 | int channel_id; |
105 | auto status = message.PushChannel(0, nullptr, &channel_id); | 107 | auto status = message.PushChannel(0, nullptr, &channel_id); |
@@ -112,7 +114,7 @@ Status<RemoteChannelHandle> ProducerQueueChannel::OnCreateConsumerQueue( | |||
112 | } | 114 | } |
113 | 115 | ||
114 | auto consumer_queue_channel = std::make_shared<ConsumerQueueChannel>( | 116 | auto consumer_queue_channel = std::make_shared<ConsumerQueueChannel>( |
115 | service(), buffer_id(), channel_id, shared_from_this()); | 117 | service(), buffer_id(), channel_id, shared_from_this(), silent); |
116 | 118 | ||
117 | // Register the existing buffers with the new consumer queue. | 119 | // Register the existing buffers with the new consumer queue. |
118 | for (size_t slot = 0; slot < BufferHubRPC::kMaxQueueCapacity; slot++) { | 120 | for (size_t slot = 0; slot < BufferHubRPC::kMaxQueueCapacity; slot++) { |
@@ -222,7 +224,7 @@ ProducerQueueChannel::AllocateBuffer(Message& message, uint32_t width, | |||
222 | 224 | ||
223 | auto producer_channel_status = | 225 | auto producer_channel_status = |
224 | ProducerChannel::Create(service(), buffer_id, width, height, layer_count, | 226 | ProducerChannel::Create(service(), buffer_id, width, height, layer_count, |
225 | format, usage, config_.meta_size_bytes); | 227 | format, usage, config_.user_metadata_size); |
226 | if (!producer_channel_status) { | 228 | if (!producer_channel_status) { |
227 | ALOGE( | 229 | ALOGE( |
228 | "ProducerQueueChannel::AllocateBuffer: Failed to create producer " | 230 | "ProducerQueueChannel::AllocateBuffer: Failed to create producer " |
diff --git a/services/vr/bufferhubd/producer_queue_channel.h b/services/vr/bufferhubd/producer_queue_channel.h index fd519c55e..e825f4777 100644 --- a/services/vr/bufferhubd/producer_queue_channel.h +++ b/services/vr/bufferhubd/producer_queue_channel.h | |||
@@ -26,7 +26,7 @@ class ProducerQueueChannel : public BufferHubChannel { | |||
26 | // Returns a handle for the service channel, as well as the size of the | 26 | // Returns a handle for the service channel, as well as the size of the |
27 | // metadata associated with the queue. | 27 | // metadata associated with the queue. |
28 | pdx::Status<pdx::RemoteChannelHandle> OnCreateConsumerQueue( | 28 | pdx::Status<pdx::RemoteChannelHandle> OnCreateConsumerQueue( |
29 | pdx::Message& message); | 29 | pdx::Message& message, bool silent); |
30 | 30 | ||
31 | pdx::Status<QueueInfo> OnGetQueueInfo(pdx::Message& message); | 31 | pdx::Status<QueueInfo> OnGetQueueInfo(pdx::Message& message); |
32 | 32 | ||