Break up and rename buffer_hub_cilent.{h, cpp}
Code in buffer_hub_cilent.{h,cpp} was the main client side
implementation of bufferhub. With years of developements, the content
of it was complicated enough to deserved separated files. Also rename
stuff for clarification.
old names:
+-------------------+
| BufferHubBuffer |
+---------^---------+
|
+------------------+ | +------------------+
| BufferProducer +----+-----+ BufferConsumer |
+------------------+ +------------------+
new names:
+-----------------+
| BufferHubBase |
+--------^--------+
|
+------------------+ | +------------------+
| ProducerBuffer +----+-----+ ConsumerBuffer |
+------------------+ +------------------+
Rename rationale:
1/ BufferProducer was originally poorly named and gets easily confused
with IGraphicBufferProducer. Actually, BufferProducer is a single
buffer that can produce (i.e. write) data into a buffer, but it
doesn't produce buffer. On the other hand, IGraphicBufferProducer
is the producer end of a BufferQueue and it is used to produce buffers.
2/ BufferConsumer was originally poorly named and gets easily confused
with IGraphicBufferConsumer. Actually, BufferConsumer is a single
buffer that can consume (i.e. read) data from a buffer, but it
doesn't consume buffer. On the other hand, IGraphicBufferConsumer
is the consumer end of a BufferQueue and it is used to consume
buffers.
3/ BufferHubBuffer is a pure base class and cannot be used
standalone. The old name suggests that it's a buffer object backed
by BufferHub, which might leads to confusion. Also, this rename is
in preparation of rename DetachedBuffer to BufferHubBuffer.
Bug: 116855254
Test: Build system
Change-Id: Id545648f5bdc7660e58f7bb49722651ae3bcca70
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 69b6422..edc9131 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -13,10 +13,13 @@
// limitations under the License.
sourceFiles = [
+ "buffer_hub_base.cpp",
"buffer_hub_client.cpp",
"buffer_hub_rpc.cpp",
+ "consumer_buffer.cpp",
"detached_buffer.cpp",
"ion_buffer.cpp",
+ "producer_buffer.cpp",
]
localIncludeFiles = [
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
new file mode 100644
index 0000000..b2bcda7
--- /dev/null
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -0,0 +1,224 @@
+#include <poll.h>
+#include <sys/epoll.h>
+
+#include <pdx/default_transport/client_channel.h>
+#include <pdx/default_transport/client_channel_factory.h>
+#include <private/dvr/buffer_hub_base.h>
+
+using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
+using android::pdx::Status;
+using android::pdx::default_transport::ClientChannel;
+using android::pdx::default_transport::ClientChannelFactory;
+
+namespace android {
+namespace dvr {
+
+BufferHubBase::BufferHubBase(LocalChannelHandle channel_handle)
+ : Client{pdx::default_transport::ClientChannel::Create(
+ std::move(channel_handle))},
+ id_(-1),
+ cid_(-1) {}
+BufferHubBase::BufferHubBase(const std::string& endpoint_path)
+ : Client{pdx::default_transport::ClientChannelFactory::Create(
+ endpoint_path)},
+ id_(-1),
+ cid_(-1) {}
+
+BufferHubBase::~BufferHubBase() {
+ if (metadata_header_ != nullptr) {
+ metadata_buffer_.Unlock();
+ }
+}
+
+Status<LocalChannelHandle> BufferHubBase::CreateConsumer() {
+ Status<LocalChannelHandle> status =
+ InvokeRemoteMethod<BufferHubRPC::NewConsumer>();
+ ALOGE_IF(!status,
+ "BufferHub::CreateConsumer: Failed to create consumer channel: %s",
+ status.GetErrorMessage().c_str());
+ return status;
+}
+
+int BufferHubBase::ImportBuffer() {
+ ATRACE_NAME("BufferHubBase::ImportBuffer");
+
+ Status<BufferDescription<LocalHandle>> status =
+ InvokeRemoteMethod<BufferHubRPC::GetBuffer>();
+ if (!status) {
+ ALOGE("BufferHubBase::ImportBuffer: Failed to get buffer: %s",
+ status.GetErrorMessage().c_str());
+ return -status.error();
+ } else if (status.get().id() < 0) {
+ ALOGE("BufferHubBase::ImportBuffer: Received an invalid id!");
+ return -EIO;
+ }
+
+ auto buffer_desc = status.take();
+
+ // Stash the buffer id to replace the value in id_.
+ const int new_id = buffer_desc.id();
+
+ // Import the buffer.
+ IonBuffer ion_buffer;
+ ALOGD_IF(TRACE, "BufferHubBase::ImportBuffer: id=%d.", buffer_desc.id());
+
+ if (const int ret = buffer_desc.ImportBuffer(&ion_buffer))
+ return ret;
+
+ // Import the metadata.
+ IonBuffer metadata_buffer;
+ if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
+ ALOGE("Failed to import metadata buffer, error=%d", ret);
+ return ret;
+ }
+ size_t metadata_buf_size = metadata_buffer.width();
+ if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
+ ALOGE("BufferHubBase::ImportBuffer: metadata buffer too small: %zu",
+ metadata_buf_size);
+ return -ENOMEM;
+ }
+
+ // If all imports succee, replace the previous buffer and id.
+ buffer_ = std::move(ion_buffer);
+ metadata_buffer_ = std::move(metadata_buffer);
+ metadata_buf_size_ = metadata_buf_size;
+ user_metadata_size_ = metadata_buf_size_ - BufferHubDefs::kMetadataHeaderSize;
+
+ void* metadata_ptr = nullptr;
+ if (const int ret =
+ metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
+ /*y=*/0, metadata_buf_size_,
+ /*height=*/1, &metadata_ptr)) {
+ ALOGE("BufferHubBase::ImportBuffer: Failed to lock metadata.");
+ return ret;
+ }
+
+ // Set up shared fences.
+ shared_acquire_fence_ = buffer_desc.take_acquire_fence();
+ shared_release_fence_ = buffer_desc.take_release_fence();
+ if (!shared_acquire_fence_ || !shared_release_fence_) {
+ ALOGE("BufferHubBase::ImportBuffer: Failed to import shared fences.");
+ return -EIO;
+ }
+
+ metadata_header_ =
+ reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
+ if (user_metadata_size_) {
+ user_metadata_ptr_ =
+ reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(metadata_ptr) +
+ BufferHubDefs::kMetadataHeaderSize);
+ } else {
+ user_metadata_ptr_ = nullptr;
+ }
+
+ id_ = new_id;
+ cid_ = buffer_desc.buffer_cid();
+ buffer_state_bit_ = buffer_desc.buffer_state_bit();
+
+ // Note that here the buffer state is mapped from shared memory as an atomic
+ // object. The std::atomic's constructor will not be called so that the
+ // original value stored in the memory region will be preserved.
+ buffer_state_ = &metadata_header_->buffer_state;
+ ALOGD_IF(TRACE,
+ "BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
+ id(), buffer_state_->load());
+ fence_state_ = &metadata_header_->fence_state;
+ ALOGD_IF(TRACE,
+ "BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx64 ".", id(),
+ fence_state_->load());
+
+ return 0;
+}
+
+int BufferHubBase::CheckMetadata(size_t user_metadata_size) const {
+ if (user_metadata_size && !user_metadata_ptr_) {
+ ALOGE("BufferHubBase::CheckMetadata: doesn't support custom metadata.");
+ return -EINVAL;
+ }
+ if (user_metadata_size > user_metadata_size_) {
+ ALOGE("BufferHubBase::CheckMetadata: too big: %zu, maximum: %zu.",
+ user_metadata_size, user_metadata_size_);
+ return -E2BIG;
+ }
+ return 0;
+}
+
+int BufferHubBase::UpdateSharedFence(const LocalHandle& new_fence,
+ const LocalHandle& shared_fence) {
+ if (pending_fence_fd_.Get() != new_fence.Get()) {
+ // First, replace the old fd if there was already one. Skipping if the new
+ // one is the same as the old.
+ if (pending_fence_fd_.IsValid()) {
+ const int ret = epoll_ctl(shared_fence.Get(), EPOLL_CTL_DEL,
+ pending_fence_fd_.Get(), nullptr);
+ ALOGW_IF(ret,
+ "BufferHubBase::UpdateSharedFence: failed to remove old fence "
+ "fd from epoll set, error: %s.",
+ strerror(errno));
+ }
+
+ if (new_fence.IsValid()) {
+ // If ready fence is valid, we put that into the epoll set.
+ epoll_event event;
+ event.events = EPOLLIN;
+ event.data.u64 = buffer_state_bit();
+ pending_fence_fd_ = new_fence.Duplicate();
+ if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(),
+ &event) < 0) {
+ const int error = errno;
+ ALOGE(
+ "BufferHubBase::UpdateSharedFence: failed to add new fence fd "
+ "into epoll set, error: %s.",
+ strerror(error));
+ return -error;
+ }
+ // Set bit in fence state to indicate that there is a fence from this
+ // producer or consumer.
+ fence_state_->fetch_or(buffer_state_bit());
+ } else {
+ // Unset bit in fence state to indicate that there is no fence, so that
+ // when consumer to acquire or producer to acquire, it knows no need to
+ // check fence for this buffer.
+ fence_state_->fetch_and(~buffer_state_bit());
+ }
+ }
+
+ return 0;
+}
+
+int BufferHubBase::Poll(int timeout_ms) {
+ ATRACE_NAME("BufferHubBase::Poll");
+ pollfd p = {event_fd(), POLLIN, 0};
+ return poll(&p, 1, timeout_ms);
+}
+
+int BufferHubBase::Lock(int usage, int x, int y, int width, int height,
+ void** address) {
+ return buffer_.Lock(usage, x, y, width, height, address);
+}
+
+int BufferHubBase::Unlock() { return buffer_.Unlock(); }
+
+int BufferHubBase::GetBlobReadWritePointer(size_t size, void** addr) {
+ int width = static_cast<int>(size);
+ int height = 1;
+ int ret = Lock(usage(), 0, 0, width, height, addr);
+ if (ret == 0)
+ Unlock();
+ return ret;
+}
+
+int BufferHubBase::GetBlobReadOnlyPointer(size_t size, void** addr) {
+ return GetBlobReadWritePointer(size, addr);
+}
+
+void BufferHubBase::GetBlobFds(int* fds, size_t* fds_count,
+ size_t max_fds_count) const {
+ size_t numFds = static_cast<size_t>(native_handle()->numFds);
+ *fds_count = std::min(max_fds_count, numFds);
+ std::copy(native_handle()->data, native_handle()->data + *fds_count, fds);
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index 577cba9..3f20024 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -1,20 +1,12 @@
-#include <private/dvr/buffer_hub_client.h>
-
-#include <log/log.h>
-#include <poll.h>
-#include <sys/epoll.h>
-#include <utils/Trace.h>
-
#include <mutex>
+#include <log/log.h>
#include <pdx/default_transport/client_channel.h>
#include <pdx/default_transport/client_channel_factory.h>
-
-#include "include/private/dvr/bufferhub_rpc.h"
+#include <private/dvr/buffer_hub_client.h>
+#include <utils/Trace.h>
using android::pdx::LocalChannelHandle;
-using android::pdx::LocalHandle;
-using android::pdx::Status;
using android::pdx::default_transport::ClientChannel;
using android::pdx::default_transport::ClientChannelFactory;
@@ -39,615 +31,5 @@
}
}
-BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle)
- : Client{pdx::default_transport::ClientChannel::Create(
- std::move(channel_handle))},
- id_(-1),
- cid_(-1) {}
-BufferHubBuffer::BufferHubBuffer(const std::string& endpoint_path)
- : Client{pdx::default_transport::ClientChannelFactory::Create(
- endpoint_path)},
- id_(-1),
- cid_(-1) {}
-
-BufferHubBuffer::~BufferHubBuffer() {
- if (metadata_header_ != nullptr) {
- metadata_buffer_.Unlock();
- }
-}
-
-Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() {
- Status<LocalChannelHandle> status =
- InvokeRemoteMethod<BufferHubRPC::NewConsumer>();
- ALOGE_IF(!status,
- "BufferHub::CreateConsumer: Failed to create consumer channel: %s",
- status.GetErrorMessage().c_str());
- return status;
-}
-
-int BufferHubBuffer::ImportBuffer() {
- ATRACE_NAME("BufferHubBuffer::ImportBuffer");
-
- Status<BufferDescription<LocalHandle>> status =
- InvokeRemoteMethod<BufferHubRPC::GetBuffer>();
- if (!status) {
- ALOGE("BufferHubBuffer::ImportBuffer: Failed to get buffer: %s",
- status.GetErrorMessage().c_str());
- return -status.error();
- } else if (status.get().id() < 0) {
- ALOGE("BufferHubBuffer::ImportBuffer: Received an invalid id!");
- return -EIO;
- }
-
- auto buffer_desc = status.take();
-
- // Stash the buffer id to replace the value in id_.
- const int new_id = buffer_desc.id();
-
- // Import the buffer.
- IonBuffer ion_buffer;
- ALOGD_IF(TRACE, "BufferHubBuffer::ImportBuffer: id=%d.", buffer_desc.id());
-
- if (const int ret = buffer_desc.ImportBuffer(&ion_buffer))
- return ret;
-
- // Import the metadata.
- IonBuffer metadata_buffer;
- if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
- ALOGE("Failed to import metadata buffer, error=%d", ret);
- return ret;
- }
- size_t metadata_buf_size = metadata_buffer.width();
- if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
- ALOGE("BufferHubBuffer::ImportBuffer: metadata buffer too small: %zu",
- metadata_buf_size);
- return -ENOMEM;
- }
-
- // If all imports succee, replace the previous buffer and id.
- buffer_ = std::move(ion_buffer);
- metadata_buffer_ = std::move(metadata_buffer);
- metadata_buf_size_ = metadata_buf_size;
- user_metadata_size_ = metadata_buf_size_ - BufferHubDefs::kMetadataHeaderSize;
-
- void* metadata_ptr = nullptr;
- if (const int ret =
- metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
- /*y=*/0, metadata_buf_size_,
- /*height=*/1, &metadata_ptr)) {
- ALOGE("BufferHubBuffer::ImportBuffer: Failed to lock metadata.");
- return ret;
- }
-
- // Set up shared fences.
- shared_acquire_fence_ = buffer_desc.take_acquire_fence();
- shared_release_fence_ = buffer_desc.take_release_fence();
- if (!shared_acquire_fence_ || !shared_release_fence_) {
- ALOGE("BufferHubBuffer::ImportBuffer: Failed to import shared fences.");
- return -EIO;
- }
-
- metadata_header_ =
- reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
- if (user_metadata_size_) {
- user_metadata_ptr_ =
- reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(metadata_ptr) +
- BufferHubDefs::kMetadataHeaderSize);
- } else {
- user_metadata_ptr_ = nullptr;
- }
-
- id_ = new_id;
- cid_ = buffer_desc.buffer_cid();
- buffer_state_bit_ = buffer_desc.buffer_state_bit();
-
- // Note that here the buffer state is mapped from shared memory as an atomic
- // object. The std::atomic's constructor will not be called so that the
- // original value stored in the memory region will be preserved.
- buffer_state_ = &metadata_header_->buffer_state;
- ALOGD_IF(TRACE,
- "BufferHubBuffer::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
- id(), buffer_state_->load());
- fence_state_ = &metadata_header_->fence_state;
- ALOGD_IF(TRACE,
- "BufferHubBuffer::ImportBuffer: id=%d, fence_state=%" PRIx64 ".",
- id(), fence_state_->load());
-
- return 0;
-}
-
-inline int BufferHubBuffer::CheckMetadata(size_t user_metadata_size) const {
- if (user_metadata_size && !user_metadata_ptr_) {
- ALOGE("BufferHubBuffer::CheckMetadata: doesn't support custom metadata.");
- return -EINVAL;
- }
- if (user_metadata_size > user_metadata_size_) {
- ALOGE("BufferHubBuffer::CheckMetadata: too big: %zu, maximum: %zu.",
- user_metadata_size, user_metadata_size_);
- return -E2BIG;
- }
- return 0;
-}
-
-int BufferHubBuffer::UpdateSharedFence(const LocalHandle& new_fence,
- const LocalHandle& shared_fence) {
- if (pending_fence_fd_.Get() != new_fence.Get()) {
- // First, replace the old fd if there was already one. Skipping if the new
- // one is the same as the old.
- if (pending_fence_fd_.IsValid()) {
- const int ret = epoll_ctl(shared_fence.Get(), EPOLL_CTL_DEL,
- pending_fence_fd_.Get(), nullptr);
- ALOGW_IF(ret,
- "BufferHubBuffer::UpdateSharedFence: failed to remove old fence "
- "fd from epoll set, error: %s.",
- strerror(errno));
- }
-
- if (new_fence.IsValid()) {
- // If ready fence is valid, we put that into the epoll set.
- epoll_event event;
- event.events = EPOLLIN;
- event.data.u64 = buffer_state_bit();
- pending_fence_fd_ = new_fence.Duplicate();
- if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(),
- &event) < 0) {
- const int error = errno;
- ALOGE(
- "BufferHubBuffer::UpdateSharedFence: failed to add new fence fd "
- "into epoll set, error: %s.",
- strerror(error));
- return -error;
- }
- // Set bit in fence state to indicate that there is a fence from this
- // producer or consumer.
- fence_state_->fetch_or(buffer_state_bit());
- } else {
- // Unset bit in fence state to indicate that there is no fence, so that
- // when consumer to acquire or producer to acquire, it knows no need to
- // check fence for this buffer.
- fence_state_->fetch_and(~buffer_state_bit());
- }
- }
-
- return 0;
-}
-
-int BufferHubBuffer::Poll(int timeout_ms) {
- ATRACE_NAME("BufferHubBuffer::Poll");
- pollfd p = {event_fd(), POLLIN, 0};
- return poll(&p, 1, timeout_ms);
-}
-
-int BufferHubBuffer::Lock(int usage, int x, int y, int width, int height,
- void** address) {
- return buffer_.Lock(usage, x, y, width, height, address);
-}
-
-int BufferHubBuffer::Unlock() { return buffer_.Unlock(); }
-
-int BufferHubBuffer::GetBlobReadWritePointer(size_t size, void** addr) {
- int width = static_cast<int>(size);
- int height = 1;
- int ret = Lock(usage(), 0, 0, width, height, addr);
- if (ret == 0)
- Unlock();
- return ret;
-}
-
-int BufferHubBuffer::GetBlobReadOnlyPointer(size_t size, void** addr) {
- return GetBlobReadWritePointer(size, addr);
-}
-
-void BufferHubBuffer::GetBlobFds(int* fds, size_t* fds_count,
- size_t max_fds_count) const {
- size_t numFds = static_cast<size_t>(native_handle()->numFds);
- *fds_count = std::min(max_fds_count, numFds);
- std::copy(native_handle()->data, native_handle()->data + *fds_count, fds);
-}
-
-BufferConsumer::BufferConsumer(LocalChannelHandle channel)
- : BASE(std::move(channel)) {
- const int ret = ImportBuffer();
- if (ret < 0) {
- ALOGE("BufferConsumer::BufferConsumer: Failed to import buffer: %s",
- strerror(-ret));
- Close(ret);
- }
-}
-
-std::unique_ptr<BufferConsumer> BufferConsumer::Import(
- LocalChannelHandle channel) {
- ATRACE_NAME("BufferConsumer::Import");
- ALOGD_IF(TRACE, "BufferConsumer::Import: channel=%d", channel.value());
- return BufferConsumer::Create(std::move(channel));
-}
-
-std::unique_ptr<BufferConsumer> BufferConsumer::Import(
- Status<LocalChannelHandle> status) {
- return Import(status ? status.take()
- : LocalChannelHandle{nullptr, -status.error()});
-}
-
-int BufferConsumer::LocalAcquire(DvrNativeBufferMetadata* out_meta,
- LocalHandle* out_fence) {
- if (!out_meta)
- return -EINVAL;
-
- // Only check producer bit and this consumer buffer's particular consumer bit.
- // The buffer is can be acquired iff: 1) producer bit is set; 2) consumer bit
- // is not set.
- uint64_t buffer_state = buffer_state_->load();
- if (!BufferHubDefs::IsBufferPosted(buffer_state, buffer_state_bit())) {
- ALOGE("BufferConsumer::LocalAcquire: not posted, id=%d state=%" PRIx64
- " buffer_state_bit=%" PRIx64 ".",
- id(), buffer_state, buffer_state_bit());
- return -EBUSY;
- }
-
- // Copy the canonical metadata.
- void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
- memcpy(out_meta, metadata_ptr, sizeof(DvrNativeBufferMetadata));
- // Fill in the user_metadata_ptr in address space of the local process.
- if (out_meta->user_metadata_size) {
- out_meta->user_metadata_ptr =
- reinterpret_cast<uint64_t>(user_metadata_ptr_);
- } else {
- out_meta->user_metadata_ptr = 0;
- }
-
- uint64_t fence_state = fence_state_->load();
- // If there is an acquire fence from producer, we need to return it.
- if (fence_state & BufferHubDefs::kProducerStateBit) {
- *out_fence = shared_acquire_fence_.Duplicate();
- }
-
- // Set the consumer bit unique to this consumer.
- BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, buffer_state_bit());
- return 0;
-}
-
-int BufferConsumer::Acquire(LocalHandle* ready_fence) {
- return Acquire(ready_fence, nullptr, 0);
-}
-
-int BufferConsumer::Acquire(LocalHandle* ready_fence, void* meta,
- size_t user_metadata_size) {
- ATRACE_NAME("BufferConsumer::Acquire");
-
- if (const int error = CheckMetadata(user_metadata_size))
- return error;
-
- DvrNativeBufferMetadata canonical_meta;
- if (const int error = LocalAcquire(&canonical_meta, ready_fence))
- return error;
-
- if (meta && user_metadata_size) {
- void* metadata_src =
- reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
- if (metadata_src) {
- memcpy(meta, metadata_src, user_metadata_size);
- } else {
- ALOGW("BufferConsumer::Acquire: no user-defined metadata.");
- }
- }
-
- auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerAcquire>();
- if (!status)
- return -status.error();
- return 0;
-}
-
-int BufferConsumer::AcquireAsync(DvrNativeBufferMetadata* out_meta,
- LocalHandle* out_fence) {
- ATRACE_NAME("BufferConsumer::AcquireAsync");
-
- if (const int error = LocalAcquire(out_meta, out_fence))
- return error;
-
- auto status = SendImpulse(BufferHubRPC::ConsumerAcquire::Opcode);
- if (!status)
- return -status.error();
- return 0;
-}
-
-int BufferConsumer::LocalRelease(const DvrNativeBufferMetadata* meta,
- const LocalHandle& release_fence) {
- if (const int error = CheckMetadata(meta->user_metadata_size))
- return error;
-
- // Check invalid state transition.
- uint64_t buffer_state = buffer_state_->load();
- if (!BufferHubDefs::IsBufferAcquired(buffer_state)) {
- ALOGE("BufferConsumer::LocalRelease: not acquired id=%d state=%" PRIx64 ".",
- id(), buffer_state);
- return -EBUSY;
- }
-
- // On release, only the user requested metadata is copied back into the shared
- // memory for metadata. Since there are multiple consumers, it doesn't make
- // sense to send the canonical metadata back to the producer. However, one of
- // the consumer can still choose to write up to user_metadata_size bytes of
- // data into user_metadata_ptr.
- if (meta->user_metadata_ptr && meta->user_metadata_size) {
- void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
- memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
- }
-
- // Send out the release fence through the shared epoll fd. Note that during
- // releasing the producer is not expected to be polling on the fence.
- if (const int error = UpdateSharedFence(release_fence, shared_release_fence_))
- return error;
-
- // For release operation, the client don't need to change the state as it's
- // bufferhubd's job to flip the produer bit once all consumers are released.
- return 0;
-}
-
-int BufferConsumer::Release(const LocalHandle& release_fence) {
- ATRACE_NAME("BufferConsumer::Release");
-
- DvrNativeBufferMetadata meta;
- if (const int error = LocalRelease(&meta, release_fence))
- return error;
-
- return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ConsumerRelease>(
- BorrowedFence(release_fence.Borrow())));
-}
-
-int BufferConsumer::ReleaseAsync() {
- DvrNativeBufferMetadata meta;
- return ReleaseAsync(&meta, LocalHandle());
-}
-
-int BufferConsumer::ReleaseAsync(const DvrNativeBufferMetadata* meta,
- const LocalHandle& release_fence) {
- ATRACE_NAME("BufferConsumer::ReleaseAsync");
-
- if (const int error = LocalRelease(meta, release_fence))
- return error;
-
- return ReturnStatusOrError(
- SendImpulse(BufferHubRPC::ConsumerRelease::Opcode));
-}
-
-int BufferConsumer::Discard() { return Release(LocalHandle()); }
-
-int BufferConsumer::SetIgnore(bool ignore) {
- return ReturnStatusOrError(
- InvokeRemoteMethod<BufferHubRPC::ConsumerSetIgnore>(ignore));
-}
-
-BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
- uint64_t usage, size_t user_metadata_size)
- : BASE(BufferHubRPC::kClientPath) {
- ATRACE_NAME("BufferProducer::BufferProducer");
- ALOGD_IF(TRACE,
- "BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u "
- "usage=%" PRIx64 " user_metadata_size=%zu",
- event_fd(), width, height, format, usage, user_metadata_size);
-
- auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
- width, height, format, usage, user_metadata_size);
- if (!status) {
- ALOGE(
- "BufferProducer::BufferProducer: Failed to create producer buffer: %s",
- status.GetErrorMessage().c_str());
- Close(-status.error());
- return;
- }
-
- const int ret = ImportBuffer();
- if (ret < 0) {
- ALOGE(
- "BufferProducer::BufferProducer: Failed to import producer buffer: %s",
- strerror(-ret));
- Close(ret);
- }
-}
-
-BufferProducer::BufferProducer(uint64_t usage, size_t size)
- : BASE(BufferHubRPC::kClientPath) {
- ATRACE_NAME("BufferProducer::BufferProducer");
- ALOGD_IF(TRACE, "BufferProducer::BufferProducer: usage=%" PRIx64 " size=%zu",
- usage, size);
- const int width = static_cast<int>(size);
- const int height = 1;
- const int format = HAL_PIXEL_FORMAT_BLOB;
- const size_t user_metadata_size = 0;
-
- auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
- width, height, format, usage, user_metadata_size);
- if (!status) {
- ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s",
- status.GetErrorMessage().c_str());
- Close(-status.error());
- return;
- }
-
- const int ret = ImportBuffer();
- if (ret < 0) {
- ALOGE(
- "BufferProducer::BufferProducer: Failed to import producer buffer: %s",
- strerror(-ret));
- Close(ret);
- }
-}
-
-BufferProducer::BufferProducer(LocalChannelHandle channel)
- : BASE(std::move(channel)) {
- const int ret = ImportBuffer();
- if (ret < 0) {
- ALOGE(
- "BufferProducer::BufferProducer: Failed to import producer buffer: %s",
- strerror(-ret));
- Close(ret);
- }
-}
-
-int BufferProducer::LocalPost(const DvrNativeBufferMetadata* meta,
- const LocalHandle& ready_fence) {
- if (const int error = CheckMetadata(meta->user_metadata_size))
- return error;
-
- // Check invalid state transition.
- uint64_t buffer_state = buffer_state_->load();
- if (!BufferHubDefs::IsBufferGained(buffer_state)) {
- ALOGE("BufferProducer::LocalPost: not gained, id=%d state=%" PRIx64 ".",
- id(), buffer_state);
- return -EBUSY;
- }
-
- // Copy the canonical metadata.
- void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
- memcpy(metadata_ptr, meta, sizeof(DvrNativeBufferMetadata));
- // Copy extra user requested metadata.
- if (meta->user_metadata_ptr && meta->user_metadata_size) {
- void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
- memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
- }
-
- // Send out the acquire fence through the shared epoll fd. Note that during
- // posting no consumer is not expected to be polling on the fence.
- if (const int error = UpdateSharedFence(ready_fence, shared_acquire_fence_))
- return error;
-
- // Set the producer bit atomically to transit into posted state.
- BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL,
- BufferHubDefs::kProducerStateBit);
- return 0;
-}
-
-int BufferProducer::Post(const LocalHandle& ready_fence, const void* meta,
- size_t user_metadata_size) {
- ATRACE_NAME("BufferProducer::Post");
-
- // Populate cononical metadata for posting.
- DvrNativeBufferMetadata canonical_meta;
- canonical_meta.user_metadata_ptr = reinterpret_cast<uint64_t>(meta);
- canonical_meta.user_metadata_size = user_metadata_size;
-
- if (const int error = LocalPost(&canonical_meta, ready_fence))
- return error;
-
- return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ProducerPost>(
- BorrowedFence(ready_fence.Borrow())));
-}
-
-int BufferProducer::PostAsync(const DvrNativeBufferMetadata* meta,
- const LocalHandle& ready_fence) {
- ATRACE_NAME("BufferProducer::PostAsync");
-
- if (const int error = LocalPost(meta, ready_fence))
- return error;
-
- return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerPost::Opcode));
-}
-
-int BufferProducer::LocalGain(DvrNativeBufferMetadata* out_meta,
- LocalHandle* out_fence) {
- uint64_t buffer_state = buffer_state_->load();
- ALOGD_IF(TRACE, "BufferProducer::LocalGain: buffer=%d, state=%" PRIx64 ".",
- id(), buffer_state);
-
- if (!out_meta)
- return -EINVAL;
-
- if (!BufferHubDefs::IsBufferReleased(buffer_state)) {
- if (BufferHubDefs::IsBufferGained(buffer_state)) {
- // We don't want to log error when gaining a newly allocated
- // buffer.
- ALOGI("BufferProducer::LocalGain: already gained id=%d.", id());
- return -EALREADY;
- }
- ALOGE("BufferProducer::LocalGain: not released id=%d state=%" PRIx64 ".",
- id(), buffer_state);
- return -EBUSY;
- }
-
- // Canonical metadata is undefined on Gain. Except for user_metadata and
- // release_fence_mask. Fill in the user_metadata_ptr in address space of the
- // local process.
- if (metadata_header_->metadata.user_metadata_size && user_metadata_ptr_) {
- out_meta->user_metadata_size =
- metadata_header_->metadata.user_metadata_size;
- out_meta->user_metadata_ptr =
- reinterpret_cast<uint64_t>(user_metadata_ptr_);
- } else {
- out_meta->user_metadata_size = 0;
- out_meta->user_metadata_ptr = 0;
- }
-
- uint64_t fence_state = fence_state_->load();
- // If there is an release fence from consumer, we need to return it.
- if (fence_state & BufferHubDefs::kConsumerStateMask) {
- *out_fence = shared_release_fence_.Duplicate();
- out_meta->release_fence_mask =
- fence_state & BufferHubDefs::kConsumerStateMask;
- }
-
- // Clear out all bits and the buffer is now back to gained state.
- buffer_state_->store(0ULL);
- return 0;
-}
-
-int BufferProducer::Gain(LocalHandle* release_fence) {
- ATRACE_NAME("BufferProducer::Gain");
-
- DvrNativeBufferMetadata meta;
- if (const int error = LocalGain(&meta, release_fence))
- return error;
-
- auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>();
- if (!status)
- return -status.error();
- return 0;
-}
-
-int BufferProducer::GainAsync(DvrNativeBufferMetadata* out_meta,
- LocalHandle* release_fence) {
- ATRACE_NAME("BufferProducer::GainAsync");
-
- if (const int error = LocalGain(out_meta, release_fence))
- return error;
-
- return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode));
-}
-
-int BufferProducer::GainAsync() {
- DvrNativeBufferMetadata meta;
- LocalHandle fence;
- return GainAsync(&meta, &fence);
-}
-
-std::unique_ptr<BufferProducer> BufferProducer::Import(
- LocalChannelHandle channel) {
- ALOGD_IF(TRACE, "BufferProducer::Import: channel=%d", channel.value());
- return BufferProducer::Create(std::move(channel));
-}
-
-std::unique_ptr<BufferProducer> BufferProducer::Import(
- Status<LocalChannelHandle> status) {
- return Import(status ? status.take()
- : LocalChannelHandle{nullptr, -status.error()});
-}
-
-Status<LocalChannelHandle> BufferProducer::Detach() {
- uint64_t buffer_state = buffer_state_->load();
- if (!BufferHubDefs::IsBufferGained(buffer_state)) {
- // Can only detach a BufferProducer when it's in gained state.
- ALOGW("BufferProducer::Detach: The buffer (id=%d, state=0x%" PRIx64
- ") is not in gained state.",
- id(), buffer_state);
- return {};
- }
-
- Status<LocalChannelHandle> status =
- InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>();
- ALOGE_IF(!status,
- "BufferProducer::Detach: Failed to detach buffer (id=%d): %s.", id(),
- status.GetErrorMessage().c_str());
- return status;
-}
-
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp
new file mode 100644
index 0000000..4e8c36b
--- /dev/null
+++ b/libs/vr/libbufferhub/consumer_buffer.cpp
@@ -0,0 +1,183 @@
+#include <private/dvr/consumer_buffer.h>
+
+using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
+using android::pdx::Status;
+
+namespace android {
+namespace dvr {
+
+ConsumerBuffer::ConsumerBuffer(LocalChannelHandle channel)
+ : BASE(std::move(channel)) {
+ const int ret = ImportBuffer();
+ if (ret < 0) {
+ ALOGE("ConsumerBuffer::ConsumerBuffer: Failed to import buffer: %s",
+ strerror(-ret));
+ Close(ret);
+ }
+}
+
+std::unique_ptr<ConsumerBuffer> ConsumerBuffer::Import(
+ LocalChannelHandle channel) {
+ ATRACE_NAME("ConsumerBuffer::Import");
+ ALOGD_IF(TRACE, "ConsumerBuffer::Import: channel=%d", channel.value());
+ return ConsumerBuffer::Create(std::move(channel));
+}
+
+std::unique_ptr<ConsumerBuffer> ConsumerBuffer::Import(
+ Status<LocalChannelHandle> status) {
+ return Import(status ? status.take()
+ : LocalChannelHandle{nullptr, -status.error()});
+}
+
+int ConsumerBuffer::LocalAcquire(DvrNativeBufferMetadata* out_meta,
+ LocalHandle* out_fence) {
+ if (!out_meta)
+ return -EINVAL;
+
+ // Only check producer bit and this consumer buffer's particular consumer bit.
+ // The buffer is can be acquired iff: 1) producer bit is set; 2) consumer bit
+ // is not set.
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferPosted(buffer_state, buffer_state_bit())) {
+ ALOGE("ConsumerBuffer::LocalAcquire: not posted, id=%d state=%" PRIx64
+ " buffer_state_bit=%" PRIx64 ".",
+ id(), buffer_state, buffer_state_bit());
+ return -EBUSY;
+ }
+
+ // Copy the canonical metadata.
+ void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
+ memcpy(out_meta, metadata_ptr, sizeof(DvrNativeBufferMetadata));
+ // Fill in the user_metadata_ptr in address space of the local process.
+ if (out_meta->user_metadata_size) {
+ out_meta->user_metadata_ptr =
+ reinterpret_cast<uint64_t>(user_metadata_ptr_);
+ } else {
+ out_meta->user_metadata_ptr = 0;
+ }
+
+ uint64_t fence_state = fence_state_->load();
+ // If there is an acquire fence from producer, we need to return it.
+ if (fence_state & BufferHubDefs::kProducerStateBit) {
+ *out_fence = shared_acquire_fence_.Duplicate();
+ }
+
+ // Set the consumer bit unique to this consumer.
+ BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, buffer_state_bit());
+ return 0;
+}
+
+int ConsumerBuffer::Acquire(LocalHandle* ready_fence) {
+ return Acquire(ready_fence, nullptr, 0);
+}
+
+int ConsumerBuffer::Acquire(LocalHandle* ready_fence, void* meta,
+ size_t user_metadata_size) {
+ ATRACE_NAME("ConsumerBuffer::Acquire");
+
+ if (const int error = CheckMetadata(user_metadata_size))
+ return error;
+
+ DvrNativeBufferMetadata canonical_meta;
+ if (const int error = LocalAcquire(&canonical_meta, ready_fence))
+ return error;
+
+ if (meta && user_metadata_size) {
+ void* metadata_src =
+ reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
+ if (metadata_src) {
+ memcpy(meta, metadata_src, user_metadata_size);
+ } else {
+ ALOGW("ConsumerBuffer::Acquire: no user-defined metadata.");
+ }
+ }
+
+ auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerAcquire>();
+ if (!status)
+ return -status.error();
+ return 0;
+}
+
+int ConsumerBuffer::AcquireAsync(DvrNativeBufferMetadata* out_meta,
+ LocalHandle* out_fence) {
+ ATRACE_NAME("ConsumerBuffer::AcquireAsync");
+
+ if (const int error = LocalAcquire(out_meta, out_fence))
+ return error;
+
+ auto status = SendImpulse(BufferHubRPC::ConsumerAcquire::Opcode);
+ if (!status)
+ return -status.error();
+ return 0;
+}
+
+int ConsumerBuffer::LocalRelease(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& release_fence) {
+ if (const int error = CheckMetadata(meta->user_metadata_size))
+ return error;
+
+ // Check invalid state transition.
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferAcquired(buffer_state)) {
+ ALOGE("ConsumerBuffer::LocalRelease: not acquired id=%d state=%" PRIx64 ".",
+ id(), buffer_state);
+ return -EBUSY;
+ }
+
+ // On release, only the user requested metadata is copied back into the shared
+ // memory for metadata. Since there are multiple consumers, it doesn't make
+ // sense to send the canonical metadata back to the producer. However, one of
+ // the consumer can still choose to write up to user_metadata_size bytes of
+ // data into user_metadata_ptr.
+ if (meta->user_metadata_ptr && meta->user_metadata_size) {
+ void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
+ memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
+ }
+
+ // Send out the release fence through the shared epoll fd. Note that during
+ // releasing the producer is not expected to be polling on the fence.
+ if (const int error = UpdateSharedFence(release_fence, shared_release_fence_))
+ return error;
+
+ // For release operation, the client don't need to change the state as it's
+ // bufferhubd's job to flip the produer bit once all consumers are released.
+ return 0;
+}
+
+int ConsumerBuffer::Release(const LocalHandle& release_fence) {
+ ATRACE_NAME("ConsumerBuffer::Release");
+
+ DvrNativeBufferMetadata meta;
+ if (const int error = LocalRelease(&meta, release_fence))
+ return error;
+
+ return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ConsumerRelease>(
+ BorrowedFence(release_fence.Borrow())));
+}
+
+int ConsumerBuffer::ReleaseAsync() {
+ DvrNativeBufferMetadata meta;
+ return ReleaseAsync(&meta, LocalHandle());
+}
+
+int ConsumerBuffer::ReleaseAsync(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& release_fence) {
+ ATRACE_NAME("ConsumerBuffer::ReleaseAsync");
+
+ if (const int error = LocalRelease(meta, release_fence))
+ return error;
+
+ return ReturnStatusOrError(
+ SendImpulse(BufferHubRPC::ConsumerRelease::Opcode));
+}
+
+int ConsumerBuffer::Discard() { return Release(LocalHandle()); }
+
+int ConsumerBuffer::SetIgnore(bool ignore) {
+ return ReturnStatusOrError(
+ InvokeRemoteMethod<BufferHubRPC::ConsumerSetIgnore>(ignore));
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
new file mode 100644
index 0000000..b75fd61
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -0,0 +1,167 @@
+#ifndef ANDROID_DVR_BUFFER_HUB_BASE_H_
+#define ANDROID_DVR_BUFFER_HUB_BASE_H_
+
+#include <vector>
+
+#include <private/dvr/bufferhub_rpc.h>
+
+namespace android {
+namespace dvr {
+
+// Base class of two types of BufferHub clients: dvr::ProducerBuffer and
+// dvr::ConsumerBuffer.
+class BufferHubBase : public pdx::Client {
+ public:
+ using LocalHandle = pdx::LocalHandle;
+ using LocalChannelHandle = pdx::LocalChannelHandle;
+ template <typename T>
+ using Status = pdx::Status<T>;
+
+ // Create a new consumer channel that is attached to the producer. Returns
+ // a file descriptor for the new channel or a negative error code.
+ Status<LocalChannelHandle> CreateConsumer();
+
+ // Polls the fd for |timeout_ms| milliseconds (-1 for infinity).
+ int Poll(int timeout_ms);
+
+ // Locks the area specified by (x, y, width, height) for a specific usage. If
+ // the usage is software then |addr| will be updated to point to the address
+ // of the buffer in virtual memory. The caller should only access/modify the
+ // pixels in the specified area. anything else is undefined behavior.
+ int Lock(int usage, int x, int y, int width, int height, void** addr);
+
+ // Must be called after Lock() when the caller has finished changing the
+ // buffer.
+ int Unlock();
+
+ // Gets a blob buffer that was created with ProducerBuffer::CreateBlob.
+ // Locking and Unlocking is handled internally. There's no need to Unlock
+ // after calling this method.
+ int GetBlobReadWritePointer(size_t size, void** addr);
+
+ // Gets a blob buffer that was created with ProducerBuffer::CreateBlob.
+ // Locking and Unlocking is handled internally. There's no need to Unlock
+ // after calling this method.
+ int GetBlobReadOnlyPointer(size_t size, void** addr);
+
+ // Returns a dup'd file descriptor for accessing the blob shared memory. The
+ // caller takes ownership of the file descriptor and must close it or pass on
+ // ownership. Some GPU API extensions can take file descriptors to bind shared
+ // memory gralloc buffers to GPU buffer objects.
+ LocalHandle GetBlobFd() const {
+ // Current GPU vendor puts the buffer allocation in one FD. If we change GPU
+ // vendors and this is the wrong fd, late-latching and EDS will very clearly
+ // stop working and we will need to correct this. The alternative is to use
+ // a GL context in the pose service to allocate this buffer or to use the
+ // ION API directly instead of gralloc.
+ return LocalHandle(dup(native_handle()->data[0]));
+ }
+
+ // Get up to |max_fds_count| file descriptors for accessing the blob shared
+ // memory. |fds_count| will contain the actual number of file descriptors.
+ void GetBlobFds(int* fds, size_t* fds_count, size_t max_fds_count) const;
+
+ using Client::event_fd;
+
+ Status<int> GetEventMask(int events) {
+ if (auto* client_channel = GetChannel()) {
+ return client_channel->GetEventMask(events);
+ } else {
+ return pdx::ErrorStatus(EINVAL);
+ }
+ }
+
+ std::vector<pdx::ClientChannel::EventSource> GetEventSources() const {
+ if (auto* client_channel = GetChannel()) {
+ return client_channel->GetEventSources();
+ } else {
+ return {};
+ }
+ }
+
+ native_handle_t* native_handle() const {
+ return const_cast<native_handle_t*>(buffer_.handle());
+ }
+
+ IonBuffer* buffer() { return &buffer_; }
+ const IonBuffer* buffer() const { return &buffer_; }
+
+ // Gets ID of the buffer client. All BufferHub clients derived from the same
+ // buffer in bufferhubd share the same buffer id.
+ int id() const { return id_; }
+
+ // Gets the channel id of the buffer client. Each BufferHub client has its
+ // system unique channel id.
+ int cid() const { return cid_; }
+
+ // Returns the buffer buffer state.
+ uint64_t buffer_state() { return buffer_state_->load(); };
+
+ // A state mask which is unique to a buffer hub client among all its siblings
+ // sharing the same concrete graphic buffer.
+ uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+
+ // The following methods return settings of the first buffer. Currently,
+ // it is only possible to create multi-buffer BufferHubBases with the same
+ // settings.
+ uint32_t width() const { return buffer_.width(); }
+ uint32_t height() const { return buffer_.height(); }
+ uint32_t stride() const { return buffer_.stride(); }
+ uint32_t format() const { return buffer_.format(); }
+ uint32_t usage() const { return buffer_.usage(); }
+ uint32_t layer_count() const { return buffer_.layer_count(); }
+
+ uint64_t GetQueueIndex() const { return metadata_header_->queue_index; }
+ void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; }
+
+ protected:
+ explicit BufferHubBase(LocalChannelHandle channel);
+ explicit BufferHubBase(const std::string& endpoint_path);
+ virtual ~BufferHubBase();
+
+ // Initialization helper.
+ int ImportBuffer();
+
+ // Check invalid metadata operation. Returns 0 if requested metadata is valid.
+ int CheckMetadata(size_t user_metadata_size) const;
+
+ // Send out the new fence by updating the shared fence (shared_release_fence
+ // for producer and shared_acquire_fence for consumer). Note that during this
+ // should only be used in LocalPost() or LocalRelease, and the shared fence
+ // shouldn't be poll'ed by the other end.
+ int UpdateSharedFence(const LocalHandle& new_fence,
+ const LocalHandle& shared_fence);
+
+ // IonBuffer that is shared between bufferhubd, producer, and consumers.
+ size_t metadata_buf_size_{0};
+ size_t user_metadata_size_{0};
+ BufferHubDefs::MetadataHeader* metadata_header_{nullptr};
+ void* user_metadata_ptr_{nullptr};
+ std::atomic<uint64_t>* buffer_state_{nullptr};
+ std::atomic<uint64_t>* fence_state_{nullptr};
+
+ LocalHandle shared_acquire_fence_;
+ LocalHandle shared_release_fence_;
+
+ // A local fence fd that holds the ownership of the fence fd on Post (for
+ // producer) and Release (for consumer).
+ LocalHandle pending_fence_fd_;
+
+ private:
+ BufferHubBase(const BufferHubBase&) = delete;
+ void operator=(const BufferHubBase&) = delete;
+
+ // Global id for the buffer that is consistent across processes. It is meant
+ // for logging and debugging purposes only and should not be used for lookup
+ // or any other functional purpose as a security precaution.
+ int id_;
+ int cid_;
+ uint64_t buffer_state_bit_{0ULL};
+ IonBuffer buffer_;
+ IonBuffer metadata_buffer_;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_BUFFER_HUB_BASE_H_
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 0b2666a..7b317d1 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -1,17 +1,10 @@
#ifndef ANDROID_DVR_BUFFER_HUB_CLIENT_H_
#define ANDROID_DVR_BUFFER_HUB_CLIENT_H_
-#include <hardware/gralloc.h>
#include <pdx/channel_handle.h>
#include <pdx/client.h>
-#include <pdx/file_handle.h>
-#include <pdx/status.h>
-
-#include <vector>
-
-#include <private/dvr/ion_buffer.h>
-
-#include "bufferhub_rpc.h"
+#include <private/dvr/consumer_buffer.h>
+#include <private/dvr/producer_buffer.h>
namespace android {
namespace dvr {
@@ -31,322 +24,6 @@
using pdx::Client::event_fd;
};
-class BufferHubBuffer : public pdx::Client {
- public:
- using LocalHandle = pdx::LocalHandle;
- using LocalChannelHandle = pdx::LocalChannelHandle;
- template <typename T>
- using Status = pdx::Status<T>;
-
- // Create a new consumer channel that is attached to the producer. Returns
- // a file descriptor for the new channel or a negative error code.
- Status<LocalChannelHandle> CreateConsumer();
-
- // Polls the fd for |timeout_ms| milliseconds (-1 for infinity).
- int Poll(int timeout_ms);
-
- // Locks the area specified by (x, y, width, height) for a specific usage. If
- // the usage is software then |addr| will be updated to point to the address
- // of the buffer in virtual memory. The caller should only access/modify the
- // pixels in the specified area. anything else is undefined behavior.
- int Lock(int usage, int x, int y, int width, int height, void** addr);
-
- // Must be called after Lock() when the caller has finished changing the
- // buffer.
- int Unlock();
-
- // Gets a blob buffer that was created with BufferProducer::CreateBlob.
- // Locking and Unlocking is handled internally. There's no need to Unlock
- // after calling this method.
- int GetBlobReadWritePointer(size_t size, void** addr);
-
- // Gets a blob buffer that was created with BufferProducer::CreateBlob.
- // Locking and Unlocking is handled internally. There's no need to Unlock
- // after calling this method.
- int GetBlobReadOnlyPointer(size_t size, void** addr);
-
- // Returns a dup'd file descriptor for accessing the blob shared memory. The
- // caller takes ownership of the file descriptor and must close it or pass on
- // ownership. Some GPU API extensions can take file descriptors to bind shared
- // memory gralloc buffers to GPU buffer objects.
- LocalHandle GetBlobFd() const {
- // Current GPU vendor puts the buffer allocation in one FD. If we change GPU
- // vendors and this is the wrong fd, late-latching and EDS will very clearly
- // stop working and we will need to correct this. The alternative is to use
- // a GL context in the pose service to allocate this buffer or to use the
- // ION API directly instead of gralloc.
- return LocalHandle(dup(native_handle()->data[0]));
- }
-
- // Get up to |max_fds_count| file descriptors for accessing the blob shared
- // memory. |fds_count| will contain the actual number of file descriptors.
- void GetBlobFds(int* fds, size_t* fds_count, size_t max_fds_count) const;
-
- using Client::event_fd;
-
- Status<int> GetEventMask(int events) {
- if (auto* client_channel = GetChannel()) {
- return client_channel->GetEventMask(events);
- } else {
- return pdx::ErrorStatus(EINVAL);
- }
- }
-
- std::vector<pdx::ClientChannel::EventSource> GetEventSources() const {
- if (auto* client_channel = GetChannel()) {
- return client_channel->GetEventSources();
- } else {
- return {};
- }
- }
-
- native_handle_t* native_handle() const {
- return const_cast<native_handle_t*>(buffer_.handle());
- }
-
- IonBuffer* buffer() { return &buffer_; }
- const IonBuffer* buffer() const { return &buffer_; }
-
- // Gets ID of the buffer client. All BufferHubBuffer clients derived from the
- // same buffer in bufferhubd share the same buffer id.
- int id() const { return id_; }
-
- // Gets the channel id of the buffer client. Each BufferHubBuffer client has
- // its system unique channel id.
- int cid() const { return cid_; }
-
- // Returns the buffer buffer state.
- uint64_t buffer_state() { return buffer_state_->load(); };
-
- // A state mask which is unique to a buffer hub client among all its siblings
- // sharing the same concrete graphic buffer.
- uint64_t buffer_state_bit() const { return buffer_state_bit_; }
-
- // The following methods return settings of the first buffer. Currently,
- // it is only possible to create multi-buffer BufferHubBuffers with the same
- // settings.
- uint32_t width() const { return buffer_.width(); }
- uint32_t height() const { return buffer_.height(); }
- uint32_t stride() const { return buffer_.stride(); }
- uint32_t format() const { return buffer_.format(); }
- uint32_t usage() const { return buffer_.usage(); }
- uint32_t layer_count() const { return buffer_.layer_count(); }
-
- uint64_t GetQueueIndex() const { return metadata_header_->queue_index; }
- void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; }
-
- protected:
- explicit BufferHubBuffer(LocalChannelHandle channel);
- explicit BufferHubBuffer(const std::string& endpoint_path);
- virtual ~BufferHubBuffer();
-
- // Initialization helper.
- int ImportBuffer();
-
- // Check invalid metadata operation. Returns 0 if requested metadata is valid.
- int CheckMetadata(size_t user_metadata_size) const;
-
- // Send out the new fence by updating the shared fence (shared_release_fence
- // for producer and shared_acquire_fence for consumer). Note that during this
- // should only be used in LocalPost() or LocalRelease, and the shared fence
- // shouldn't be poll'ed by the other end.
- int UpdateSharedFence(const LocalHandle& new_fence,
- const LocalHandle& shared_fence);
-
- // IonBuffer that is shared between bufferhubd, producer, and consumers.
- size_t metadata_buf_size_{0};
- size_t user_metadata_size_{0};
- BufferHubDefs::MetadataHeader* metadata_header_{nullptr};
- void* user_metadata_ptr_{nullptr};
- std::atomic<uint64_t>* buffer_state_{nullptr};
- std::atomic<uint64_t>* fence_state_{nullptr};
-
- LocalHandle shared_acquire_fence_;
- LocalHandle shared_release_fence_;
-
- // A local fence fd that holds the ownership of the fence fd on Post (for
- // producer) and Release (for consumer).
- LocalHandle pending_fence_fd_;
-
- private:
- BufferHubBuffer(const BufferHubBuffer&) = delete;
- void operator=(const BufferHubBuffer&) = delete;
-
- // Global id for the buffer that is consistent across processes. It is meant
- // for logging and debugging purposes only and should not be used for lookup
- // or any other functional purpose as a security precaution.
- int id_;
- int cid_;
- uint64_t buffer_state_bit_{0ULL};
- IonBuffer buffer_;
- IonBuffer metadata_buffer_;
-};
-
-// This represents a writable buffer. Calling Post notifies all clients and
-// makes the buffer read-only. Call Gain to acquire write access. A buffer
-// may have many consumers.
-//
-// The user of BufferProducer is responsible with making sure that the Post() is
-// done with the correct metadata type and size. The user is also responsible
-// for making sure that remote ends (BufferConsumers) are also using the correct
-// metadata when acquiring the buffer. The API guarantees that a Post() with a
-// metadata of wrong size will fail. However, it currently does not do any
-// type checking.
-// The API also assumes that metadata is a serializable type (plain old data).
-class BufferProducer : public pdx::ClientBase<BufferProducer, BufferHubBuffer> {
- public:
- // Imports a bufferhub producer channel, assuming ownership of its handle.
- static std::unique_ptr<BufferProducer> Import(LocalChannelHandle channel);
- static std::unique_ptr<BufferProducer> Import(
- Status<LocalChannelHandle> status);
-
- // Asynchronously posts a buffer. The fence and metadata are passed to
- // consumer via shared fd and shared memory.
- int PostAsync(const DvrNativeBufferMetadata* meta,
- const LocalHandle& ready_fence);
-
- // Post this buffer, passing |ready_fence| to the consumers. The bytes in
- // |meta| are passed unaltered to the consumers. The producer must not modify
- // the buffer until it is re-gained.
- // This returns zero or a negative unix error code.
- int Post(const LocalHandle& ready_fence, const void* meta,
- size_t user_metadata_size);
-
- int Post(const LocalHandle& ready_fence) {
- return Post(ready_fence, nullptr, 0);
- }
-
- template <typename Meta, typename = typename std::enable_if<
- !std::is_void<Meta>::value>::type>
- int Post(const LocalHandle& ready_fence, const Meta& meta) {
- return Post(ready_fence, &meta, sizeof(meta));
- }
-
- // Attempt to re-gain the buffer for writing. If |release_fence| is valid, it
- // must be waited on before using the buffer. If it is not valid then the
- // buffer is free for immediate use. This call will only succeed if the buffer
- // is in the released state.
- // This returns zero or a negative unix error code.
- int Gain(LocalHandle* release_fence);
- int GainAsync();
-
- // Asynchronously marks a released buffer as gained. This method is similar to
- // the synchronous version above, except that it does not wait for BufferHub
- // to acknowledge success or failure. Because of the asynchronous nature of
- // the underlying message, no error is returned if this method is called when
- // the buffer is in an incorrect state. Returns zero if sending the message
- // succeeded, or a negative errno code if local error check fails.
- int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
-
- // Detaches a ProducerBuffer from an existing producer/consumer set. Can only
- // be called when a producer buffer has exclusive access to the buffer (i.e.
- // in the gain'ed state). On the successful return of the IPC call, a new
- // LocalChannelHandle representing a detached buffer will be returned and all
- // existing producer and consumer channels will be closed. Further IPCs
- // towards those channels will return error.
- Status<LocalChannelHandle> Detach();
-
- private:
- friend BASE;
-
- // Constructors are automatically exposed through BufferProducer::Create(...)
- // static template methods inherited from ClientBase, which take the same
- // arguments as the constructors.
-
- // Constructs a buffer with the given geometry and parameters.
- BufferProducer(uint32_t width, uint32_t height, uint32_t format,
- uint64_t usage, size_t metadata_size = 0);
-
- // Constructs a blob (flat) buffer with the given usage flags.
- BufferProducer(uint64_t usage, size_t size);
-
- // Imports the given file handle to a producer channel, taking ownership.
- explicit BufferProducer(LocalChannelHandle channel);
-
- // Local state transition helpers.
- int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
- int LocalPost(const DvrNativeBufferMetadata* meta,
- const LocalHandle& ready_fence);
-};
-
-// This is a connection to a producer buffer, which can be located in another
-// application. When that buffer is Post()ed, this fd will be signaled and
-// Acquire allows read access. The user is responsible for making sure that
-// Acquire is called with the correct metadata structure. The only guarantee the
-// API currently provides is that an Acquire() with metadata of the wrong size
-// will fail.
-class BufferConsumer : public pdx::ClientBase<BufferConsumer, BufferHubBuffer> {
- public:
- // This call assumes ownership of |fd|.
- static std::unique_ptr<BufferConsumer> Import(LocalChannelHandle channel);
- static std::unique_ptr<BufferConsumer> Import(
- Status<LocalChannelHandle> status);
-
- // Attempt to retrieve a post event from buffer hub. If successful,
- // |ready_fence| will be set to a fence to wait on until the buffer is ready.
- // This call will only succeed after the fd is signalled. This call may be
- // performed as an alternative to the Acquire() with metadata. In such cases
- // the metadata is not read.
- //
- // This returns zero or negative unix error code.
- int Acquire(LocalHandle* ready_fence);
-
- // Attempt to retrieve a post event from buffer hub. If successful,
- // |ready_fence| is set to a fence signaling that the contents of the buffer
- // are available. This call will only succeed if the buffer is in the posted
- // state.
- // Returns zero on success, or a negative errno code otherwise.
- int Acquire(LocalHandle* ready_fence, void* meta, size_t user_metadata_size);
-
- // Attempt to retrieve a post event from buffer hub. If successful,
- // |ready_fence| is set to a fence to wait on until the buffer is ready. This
- // call will only succeed after the fd is signaled. This returns zero or a
- // negative unix error code.
- template <typename Meta>
- int Acquire(LocalHandle* ready_fence, Meta* meta) {
- return Acquire(ready_fence, meta, sizeof(*meta));
- }
-
- // Asynchronously acquires a bufer.
- int AcquireAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
-
- // This should be called after a successful Acquire call. If the fence is
- // valid the fence determines the buffer usage, otherwise the buffer is
- // released immediately.
- // This returns zero or a negative unix error code.
- int Release(const LocalHandle& release_fence);
- int ReleaseAsync();
-
- // Asynchronously releases a buffer. Similar to the synchronous version above,
- // except that it does not wait for BufferHub to reply with success or error.
- // The fence and metadata are passed to consumer via shared fd and shared
- // memory.
- int ReleaseAsync(const DvrNativeBufferMetadata* meta,
- const LocalHandle& release_fence);
-
- // May be called after or instead of Acquire to indicate that the consumer
- // does not need to access the buffer this cycle. This returns zero or a
- // negative unix error code.
- int Discard();
-
- // When set, this consumer is no longer notified when this buffer is
- // available. The system behaves as if Discard() is immediately called
- // whenever the buffer is posted. If ignore is set to true while a buffer is
- // pending, it will act as if Discard() was also called.
- // This returns zero or a negative unix error code.
- int SetIgnore(bool ignore);
-
- private:
- friend BASE;
-
- explicit BufferConsumer(LocalChannelHandle channel);
-
- // Local state transition helpers.
- int LocalAcquire(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
- int LocalRelease(const DvrNativeBufferMetadata* meta,
- const LocalHandle& release_fence);
-};
-
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index e163216..225914a 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -113,13 +113,15 @@
BufferDescription(BufferDescription&& other) = default;
BufferDescription& operator=(BufferDescription&& other) = default;
- // ID of the buffer client. All BufferHubBuffer clients derived from the same
- // buffer in bufferhubd share the same buffer id.
+ // ID of the buffer client. All BufferHub clients derived from the same buffer
+ // in bufferhubd share the same buffer id.
int id() const { return id_; }
- // Channel ID of the buffer client. Each BufferHubBuffer client has its system
+
+ // Channel ID of the buffer client. Each BufferHub client has its system
// unique channel id.
int buffer_cid() const { return buffer_cid_; }
- // State mask of the buffer client. Each BufferHubBuffer client backed by the
+
+ // State mask of the buffer client. Each BufferHub client backed by the
// same buffer channel has uniqued state bit among its siblings. For a
// producer buffer the bit must be kProducerStateBit; for a consumer the bit
// must be one of the kConsumerStateMask.
diff --git a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
new file mode 100644
index 0000000..089eff8
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
@@ -0,0 +1,100 @@
+#ifndef ANDROID_DVR_CONSUMER_BUFFER_H_
+#define ANDROID_DVR_CONSUMER_BUFFER_H_
+
+#include <private/dvr/buffer_hub_base.h>
+
+namespace android {
+namespace dvr {
+
+// BufferConsumer was originally poorly named and gets easily confused with
+// IGraphicBufferConsumer. Actually, BufferConsumer is a single buffer that can
+// consume (i.e. read) data from a buffer, but it doesn't consume buffer. On
+// the other hand, IGraphicBufferConsumer is the consumer end of a BufferQueue
+// and it is used to consume buffers.
+//
+// TODO(b/116855254): Remove this typedef once rename is complete in other
+// projects and/or branches.
+typedef class ConsumerBuffer BufferConsumer;
+
+// This is a connection to a producer buffer, which can be located in another
+// application. When that buffer is Post()ed, this fd will be signaled and
+// Acquire allows read access. The user is responsible for making sure that
+// Acquire is called with the correct metadata structure. The only guarantee the
+// API currently provides is that an Acquire() with metadata of the wrong size
+// will fail.
+class ConsumerBuffer : public pdx::ClientBase<ConsumerBuffer, BufferHubBase> {
+ public:
+ // This call assumes ownership of |fd|.
+ static std::unique_ptr<ConsumerBuffer> Import(LocalChannelHandle channel);
+ static std::unique_ptr<ConsumerBuffer> Import(
+ Status<LocalChannelHandle> status);
+
+ // Attempt to retrieve a post event from buffer hub. If successful,
+ // |ready_fence| will be set to a fence to wait on until the buffer is ready.
+ // This call will only succeed after the fd is signalled. This call may be
+ // performed as an alternative to the Acquire() with metadata. In such cases
+ // the metadata is not read.
+ //
+ // This returns zero or negative unix error code.
+ int Acquire(LocalHandle* ready_fence);
+
+ // Attempt to retrieve a post event from buffer hub. If successful,
+ // |ready_fence| is set to a fence signaling that the contents of the buffer
+ // are available. This call will only succeed if the buffer is in the posted
+ // state.
+ // Returns zero on success, or a negative errno code otherwise.
+ int Acquire(LocalHandle* ready_fence, void* meta, size_t user_metadata_size);
+
+ // Attempt to retrieve a post event from buffer hub. If successful,
+ // |ready_fence| is set to a fence to wait on until the buffer is ready. This
+ // call will only succeed after the fd is signaled. This returns zero or a
+ // negative unix error code.
+ template <typename Meta>
+ int Acquire(LocalHandle* ready_fence, Meta* meta) {
+ return Acquire(ready_fence, meta, sizeof(*meta));
+ }
+
+ // Asynchronously acquires a bufer.
+ int AcquireAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+
+ // This should be called after a successful Acquire call. If the fence is
+ // valid the fence determines the buffer usage, otherwise the buffer is
+ // released immediately.
+ // This returns zero or a negative unix error code.
+ int Release(const LocalHandle& release_fence);
+ int ReleaseAsync();
+
+ // Asynchronously releases a buffer. Similar to the synchronous version above,
+ // except that it does not wait for BufferHub to reply with success or error.
+ // The fence and metadata are passed to consumer via shared fd and shared
+ // memory.
+ int ReleaseAsync(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& release_fence);
+
+ // May be called after or instead of Acquire to indicate that the consumer
+ // does not need to access the buffer this cycle. This returns zero or a
+ // negative unix error code.
+ int Discard();
+
+ // When set, this consumer is no longer notified when this buffer is
+ // available. The system behaves as if Discard() is immediately called
+ // whenever the buffer is posted. If ignore is set to true while a buffer is
+ // pending, it will act as if Discard() was also called.
+ // This returns zero or a negative unix error code.
+ int SetIgnore(bool ignore);
+
+ private:
+ friend BASE;
+
+ explicit ConsumerBuffer(LocalChannelHandle channel);
+
+ // Local state transition helpers.
+ int LocalAcquire(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+ int LocalRelease(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& release_fence);
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_CONSUMER_BUFFER_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
new file mode 100644
index 0000000..b5e1c5b
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
@@ -0,0 +1,109 @@
+#ifndef ANDROID_DVR_PRODUCER_BUFFER_H_
+#define ANDROID_DVR_PRODUCER_BUFFER_H_
+
+#include <private/dvr/buffer_hub_base.h>
+
+namespace android {
+namespace dvr {
+
+// BufferProducer was originally poorly named and gets easily confused with
+// IGraphicBufferProducer. Actually, BufferProducer is a single buffer that can
+// produce (i.e. write) data into a buffer, but it doesn't produce buffer. On
+// the other hand, IGraphicBufferProducer is the producer end of a BufferQueue
+// and it is used to produce buffers.
+//
+// TODO(b/116855254): Remove this typedef once rename is complete in other
+// projects and/or branches.
+typedef class ProducerBuffer BufferProducer;
+
+// This represents a writable buffer. Calling Post notifies all clients and
+// makes the buffer read-only. Call Gain to acquire write access. A buffer
+// may have many consumers.
+//
+// The user of ProducerBuffer is responsible with making sure that the Post() is
+// done with the correct metadata type and size. The user is also responsible
+// for making sure that remote ends (BufferConsumers) are also using the correct
+// metadata when acquiring the buffer. The API guarantees that a Post() with a
+// metadata of wrong size will fail. However, it currently does not do any
+// type checking.
+// The API also assumes that metadata is a serializable type (plain old data).
+class ProducerBuffer : public pdx::ClientBase<ProducerBuffer, BufferHubBase> {
+ public:
+ // Imports a bufferhub producer channel, assuming ownership of its handle.
+ static std::unique_ptr<ProducerBuffer> Import(LocalChannelHandle channel);
+ static std::unique_ptr<ProducerBuffer> Import(
+ Status<LocalChannelHandle> status);
+
+ // Asynchronously posts a buffer. The fence and metadata are passed to
+ // consumer via shared fd and shared memory.
+ int PostAsync(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& ready_fence);
+
+ // Post this buffer, passing |ready_fence| to the consumers. The bytes in
+ // |meta| are passed unaltered to the consumers. The producer must not modify
+ // the buffer until it is re-gained.
+ // This returns zero or a negative unix error code.
+ int Post(const LocalHandle& ready_fence, const void* meta,
+ size_t user_metadata_size);
+
+ int Post(const LocalHandle& ready_fence) {
+ return Post(ready_fence, nullptr, 0);
+ }
+
+ template <typename Meta, typename = typename std::enable_if<
+ !std::is_void<Meta>::value>::type>
+ int Post(const LocalHandle& ready_fence, const Meta& meta) {
+ return Post(ready_fence, &meta, sizeof(meta));
+ }
+
+ // Attempt to re-gain the buffer for writing. If |release_fence| is valid, it
+ // must be waited on before using the buffer. If it is not valid then the
+ // buffer is free for immediate use. This call will only succeed if the buffer
+ // is in the released state.
+ // This returns zero or a negative unix error code.
+ int Gain(LocalHandle* release_fence);
+ int GainAsync();
+
+ // Asynchronously marks a released buffer as gained. This method is similar to
+ // the synchronous version above, except that it does not wait for BufferHub
+ // to acknowledge success or failure. Because of the asynchronous nature of
+ // the underlying message, no error is returned if this method is called when
+ // the buffer is in an incorrect state. Returns zero if sending the message
+ // succeeded, or a negative errno code if local error check fails.
+ int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+
+ // Detaches a ProducerBuffer from an existing producer/consumer set. Can only
+ // be called when a producer buffer has exclusive access to the buffer (i.e.
+ // in the gain'ed state). On the successful return of the IPC call, a new
+ // LocalChannelHandle representing a detached buffer will be returned and all
+ // existing producer and consumer channels will be closed. Further IPCs
+ // towards those channels will return error.
+ Status<LocalChannelHandle> Detach();
+
+ private:
+ friend BASE;
+
+ // Constructors are automatically exposed through ProducerBuffer::Create(...)
+ // static template methods inherited from ClientBase, which take the same
+ // arguments as the constructors.
+
+ // Constructs a buffer with the given geometry and parameters.
+ ProducerBuffer(uint32_t width, uint32_t height, uint32_t format,
+ uint64_t usage, size_t metadata_size = 0);
+
+ // Constructs a blob (flat) buffer with the given usage flags.
+ ProducerBuffer(uint64_t usage, size_t size);
+
+ // Imports the given file handle to a producer channel, taking ownership.
+ explicit ProducerBuffer(LocalChannelHandle channel);
+
+ // Local state transition helpers.
+ int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+ int LocalPost(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& ready_fence);
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_PRODUCER_BUFFER_H_
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
new file mode 100644
index 0000000..c4f1a3b
--- /dev/null
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -0,0 +1,243 @@
+#include <private/dvr/producer_buffer.h>
+
+using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
+using android::pdx::Status;
+
+namespace android {
+namespace dvr {
+
+ProducerBuffer::ProducerBuffer(uint32_t width, uint32_t height, uint32_t format,
+ uint64_t usage, size_t user_metadata_size)
+ : BASE(BufferHubRPC::kClientPath) {
+ ATRACE_NAME("ProducerBuffer::ProducerBuffer");
+ ALOGD_IF(TRACE,
+ "ProducerBuffer::ProducerBuffer: fd=%d width=%u height=%u format=%u "
+ "usage=%" PRIx64 " user_metadata_size=%zu",
+ event_fd(), width, height, format, usage, user_metadata_size);
+
+ auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
+ width, height, format, usage, user_metadata_size);
+ if (!status) {
+ ALOGE(
+ "ProducerBuffer::ProducerBuffer: Failed to create producer buffer: %s",
+ status.GetErrorMessage().c_str());
+ Close(-status.error());
+ return;
+ }
+
+ const int ret = ImportBuffer();
+ if (ret < 0) {
+ ALOGE(
+ "ProducerBuffer::ProducerBuffer: Failed to import producer buffer: %s",
+ strerror(-ret));
+ Close(ret);
+ }
+}
+
+ProducerBuffer::ProducerBuffer(uint64_t usage, size_t size)
+ : BASE(BufferHubRPC::kClientPath) {
+ ATRACE_NAME("ProducerBuffer::ProducerBuffer");
+ ALOGD_IF(TRACE, "ProducerBuffer::ProducerBuffer: usage=%" PRIx64 " size=%zu",
+ usage, size);
+ const int width = static_cast<int>(size);
+ const int height = 1;
+ const int format = HAL_PIXEL_FORMAT_BLOB;
+ const size_t user_metadata_size = 0;
+
+ auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
+ width, height, format, usage, user_metadata_size);
+ if (!status) {
+ ALOGE("ProducerBuffer::ProducerBuffer: Failed to create blob: %s",
+ status.GetErrorMessage().c_str());
+ Close(-status.error());
+ return;
+ }
+
+ const int ret = ImportBuffer();
+ if (ret < 0) {
+ ALOGE(
+ "ProducerBuffer::ProducerBuffer: Failed to import producer buffer: %s",
+ strerror(-ret));
+ Close(ret);
+ }
+}
+
+ProducerBuffer::ProducerBuffer(LocalChannelHandle channel)
+ : BASE(std::move(channel)) {
+ const int ret = ImportBuffer();
+ if (ret < 0) {
+ ALOGE(
+ "ProducerBuffer::ProducerBuffer: Failed to import producer buffer: %s",
+ strerror(-ret));
+ Close(ret);
+ }
+}
+
+int ProducerBuffer::LocalPost(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& ready_fence) {
+ if (const int error = CheckMetadata(meta->user_metadata_size))
+ return error;
+
+ // Check invalid state transition.
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+ ALOGE("ProducerBuffer::LocalPost: not gained, id=%d state=%" PRIx64 ".",
+ id(), buffer_state);
+ return -EBUSY;
+ }
+
+ // Copy the canonical metadata.
+ void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
+ memcpy(metadata_ptr, meta, sizeof(DvrNativeBufferMetadata));
+ // Copy extra user requested metadata.
+ if (meta->user_metadata_ptr && meta->user_metadata_size) {
+ void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
+ memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
+ }
+
+ // Send out the acquire fence through the shared epoll fd. Note that during
+ // posting no consumer is not expected to be polling on the fence.
+ if (const int error = UpdateSharedFence(ready_fence, shared_acquire_fence_))
+ return error;
+
+ // Set the producer bit atomically to transit into posted state.
+ BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL,
+ BufferHubDefs::kProducerStateBit);
+ return 0;
+}
+
+int ProducerBuffer::Post(const LocalHandle& ready_fence, const void* meta,
+ size_t user_metadata_size) {
+ ATRACE_NAME("ProducerBuffer::Post");
+
+ // Populate cononical metadata for posting.
+ DvrNativeBufferMetadata canonical_meta;
+ canonical_meta.user_metadata_ptr = reinterpret_cast<uint64_t>(meta);
+ canonical_meta.user_metadata_size = user_metadata_size;
+
+ if (const int error = LocalPost(&canonical_meta, ready_fence))
+ return error;
+
+ return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ProducerPost>(
+ BorrowedFence(ready_fence.Borrow())));
+}
+
+int ProducerBuffer::PostAsync(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& ready_fence) {
+ ATRACE_NAME("ProducerBuffer::PostAsync");
+
+ if (const int error = LocalPost(meta, ready_fence))
+ return error;
+
+ return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerPost::Opcode));
+}
+
+int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta,
+ LocalHandle* out_fence) {
+ uint64_t buffer_state = buffer_state_->load();
+ ALOGD_IF(TRACE, "ProducerBuffer::LocalGain: buffer=%d, state=%" PRIx64 ".",
+ id(), buffer_state);
+
+ if (!out_meta)
+ return -EINVAL;
+
+ if (!BufferHubDefs::IsBufferReleased(buffer_state)) {
+ if (BufferHubDefs::IsBufferGained(buffer_state)) {
+ // We don't want to log error when gaining a newly allocated
+ // buffer.
+ ALOGI("ProducerBuffer::LocalGain: already gained id=%d.", id());
+ return -EALREADY;
+ }
+ ALOGE("ProducerBuffer::LocalGain: not released id=%d state=%" PRIx64 ".",
+ id(), buffer_state);
+ return -EBUSY;
+ }
+
+ // Canonical metadata is undefined on Gain. Except for user_metadata and
+ // release_fence_mask. Fill in the user_metadata_ptr in address space of the
+ // local process.
+ if (metadata_header_->metadata.user_metadata_size && user_metadata_ptr_) {
+ out_meta->user_metadata_size =
+ metadata_header_->metadata.user_metadata_size;
+ out_meta->user_metadata_ptr =
+ reinterpret_cast<uint64_t>(user_metadata_ptr_);
+ } else {
+ out_meta->user_metadata_size = 0;
+ out_meta->user_metadata_ptr = 0;
+ }
+
+ uint64_t fence_state = fence_state_->load();
+ // If there is an release fence from consumer, we need to return it.
+ if (fence_state & BufferHubDefs::kConsumerStateMask) {
+ *out_fence = shared_release_fence_.Duplicate();
+ out_meta->release_fence_mask =
+ fence_state & BufferHubDefs::kConsumerStateMask;
+ }
+
+ // Clear out all bits and the buffer is now back to gained state.
+ buffer_state_->store(0ULL);
+ return 0;
+}
+
+int ProducerBuffer::Gain(LocalHandle* release_fence) {
+ ATRACE_NAME("ProducerBuffer::Gain");
+
+ DvrNativeBufferMetadata meta;
+ if (const int error = LocalGain(&meta, release_fence))
+ return error;
+
+ auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>();
+ if (!status)
+ return -status.error();
+ return 0;
+}
+
+int ProducerBuffer::GainAsync(DvrNativeBufferMetadata* out_meta,
+ LocalHandle* release_fence) {
+ ATRACE_NAME("ProducerBuffer::GainAsync");
+
+ if (const int error = LocalGain(out_meta, release_fence))
+ return error;
+
+ return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode));
+}
+
+int ProducerBuffer::GainAsync() {
+ DvrNativeBufferMetadata meta;
+ LocalHandle fence;
+ return GainAsync(&meta, &fence);
+}
+
+std::unique_ptr<ProducerBuffer> ProducerBuffer::Import(
+ LocalChannelHandle channel) {
+ ALOGD_IF(TRACE, "ProducerBuffer::Import: channel=%d", channel.value());
+ return ProducerBuffer::Create(std::move(channel));
+}
+
+std::unique_ptr<ProducerBuffer> ProducerBuffer::Import(
+ Status<LocalChannelHandle> status) {
+ return Import(status ? status.take()
+ : LocalChannelHandle{nullptr, -status.error()});
+}
+
+Status<LocalChannelHandle> ProducerBuffer::Detach() {
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+ // Can only detach a ProducerBuffer when it's in gained state.
+ ALOGW("ProducerBuffer::Detach: The buffer (id=%d, state=0x%" PRIx64
+ ") is not in gained state.",
+ id(), buffer_state);
+ return {};
+ }
+
+ Status<LocalChannelHandle> status =
+ InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>();
+ ALOGE_IF(!status,
+ "ProducerBuffer::Detach: Failed to detach buffer (id=%d): %s.", id(),
+ status.GetErrorMessage().c_str());
+ return status;
+}
+
+} // namespace dvr
+} // namespace android