blob: 0ea77c85fbe9234a55b0f0116ad45bf6edebaee3 [file] [log] [blame]
#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"
namespace android {
namespace dvr {
class BufferHubClient : public pdx::Client {
public:
BufferHubClient();
explicit BufferHubClient(pdx::LocalChannelHandle channel_handle);
bool IsValid() const;
pdx::LocalChannelHandle TakeChannelHandle();
using pdx::Client::Close;
using pdx::Client::GetChannel;
using pdx::Client::InvokeRemoteMethod;
using pdx::Client::IsConnected;
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_; }
int id() const { return id_; }
// 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_;
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);
template <typename Meta,
typename = typename std::enable_if<std::is_void<Meta>::value>::type>
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
#endif // ANDROID_DVR_BUFFER_HUB_CLIENT_H_