Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6fcf2fc authored by Jiwen 'Steve' Cai's avatar Jiwen 'Steve' Cai Committed by Jiwen Cai
Browse files

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
parent d3788632
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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 = [
+224 −0
Original line number Diff line number Diff line
#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
+3 −621

File changed.

Preview size limit exceeded, changes collapsed.

+183 −0
Original line number Diff line number Diff line
#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
+167 −0
Original line number Diff line number Diff line
#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_
Loading