Loading cmds/atrace/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ cc_binary { "libhidltransport", "liblog", "libutils", "libcutils", "libz", "libbase", ], Loading libs/vr/libbufferhub/Android.bp +6 −3 Original line number Diff line number Diff line Loading @@ -37,7 +37,8 @@ sharedLibraries = [ "libnativewindow" ] HeaderLibraries = [ headerLibraries = [ "libdvr_headers", "libnativebase_headers", ] Loading @@ -45,12 +46,13 @@ cc_library { srcs: sourceFiles, cflags: [ "-DLOG_TAG=\"libbufferhub\"", "-DTRACE=0" "-DTRACE=0", "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", ], export_include_dirs: localIncludeFiles, static_libs: staticLibraries, shared_libs: sharedLibraries, header_libs: HeaderLibraries, header_libs: headerLibraries, name: "libbufferhub", export_header_lib_headers: [ "libnativebase_headers", Loading @@ -62,6 +64,7 @@ cc_test { srcs: ["bufferhub_tests.cpp"], static_libs: ["libbufferhub"] + staticLibraries, shared_libs: sharedLibraries, header_libs: headerLibraries, name: "bufferhub_tests", } libs/vr/libbufferhub/buffer_hub_client.cpp +385 −43 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ #include <log/log.h> #include <poll.h> #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <sys/epoll.h> #include <utils/Trace.h> #include <mutex> Loading @@ -12,9 +12,8 @@ #include "include/private/dvr/bufferhub_rpc.h" using android::pdx::LocalHandle; using android::pdx::LocalChannelHandle; using android::pdx::rpc::WrapBuffer; using android::pdx::LocalHandle; using android::pdx::Status; namespace android { Loading @@ -29,7 +28,11 @@ BufferHubBuffer::BufferHubBuffer(const std::string& endpoint_path) endpoint_path)}, id_(-1) {} BufferHubBuffer::~BufferHubBuffer() {} BufferHubBuffer::~BufferHubBuffer() { if (metadata_header_ != nullptr) { metadata_buffer_.Unlock(); } } Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() { Status<LocalChannelHandle> status = Loading @@ -43,7 +46,7 @@ Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() { int BufferHubBuffer::ImportBuffer() { ATRACE_NAME("BufferHubBuffer::ImportBuffer"); Status<NativeBufferHandle<LocalHandle>> status = Status<BufferDescription<LocalHandle>> status = InvokeRemoteMethod<BufferHubRPC::GetBuffer>(); if (!status) { ALOGE("BufferHubBuffer::ImportBuffer: Failed to get buffer: %s", Loading @@ -54,24 +57,135 @@ int BufferHubBuffer::ImportBuffer() { return -EIO; } auto buffer_handle = status.take(); auto buffer_desc = status.take(); // Stash the buffer id to replace the value in id_. const int new_id = buffer_handle.id(); const int new_id = buffer_desc.id(); // Import the buffer. IonBuffer ion_buffer; ALOGD_IF( TRACE, "BufferHubBuffer::ImportBuffer: id=%d FdCount=%zu IntCount=%zu", buffer_handle.id(), buffer_handle.FdCount(), buffer_handle.IntCount()); ALOGD_IF(TRACE, "BufferHubBuffer::ImportBuffer: id=%d.", buffer_desc.id()); const int ret = buffer_handle.Import(&ion_buffer); if (ret < 0) if (const int ret = buffer_desc.ImportBuffer(&ion_buffer)) return ret; // If the import succeeds, replace the previous buffer and id. // 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; 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; } Loading Loading @@ -131,31 +245,144 @@ std::unique_ptr<BufferConsumer> BufferConsumer::Import( : 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 meta_size_bytes) { size_t user_metadata_size) { ATRACE_NAME("BufferConsumer::Acquire"); LocalFence fence; auto return_value = std::make_pair(std::ref(fence), WrapBuffer(meta, meta_size_bytes)); auto status = InvokeRemoteMethodInPlace<BufferHubRPC::ConsumerAcquire>( &return_value, meta_size_bytes); if (status && ready_fence) *ready_fence = fence.take(); return status ? 0 : -status.error(); 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)); } Loading @@ -168,24 +395,25 @@ int BufferConsumer::SetIgnore(bool ignore) { } BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, uint32_t usage, size_t metadata_size) : BufferProducer(width, height, format, usage, usage, metadata_size) {} uint32_t usage, size_t user_metadata_size) : BufferProducer(width, height, format, usage, usage, user_metadata_size) {} BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, uint64_t producer_usage, uint64_t consumer_usage, size_t metadata_size) 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 " "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 " metadata_size=%zu", " user_metadata_size=%zu", event_fd(), width, height, format, producer_usage, consumer_usage, metadata_size); user_metadata_size); // (b/37881101) Deprecate producer/consumer usage auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( width, height, format, (producer_usage | consumer_usage), metadata_size); width, height, format, (producer_usage | consumer_usage), user_metadata_size); if (!status) { ALOGE( "BufferProducer::BufferProducer: Failed to create producer buffer: %s", Loading @@ -206,27 +434,28 @@ BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, BufferProducer::BufferProducer(const std::string& name, int user_id, int group_id, uint32_t width, uint32_t height, uint32_t format, uint32_t usage, size_t meta_size_bytes) size_t user_metadata_size) : BufferProducer(name, user_id, group_id, width, height, format, usage, usage, meta_size_bytes) {} usage, user_metadata_size) {} BufferProducer::BufferProducer(const std::string& name, int user_id, int group_id, uint32_t width, uint32_t height, uint32_t format, uint64_t producer_usage, uint64_t consumer_usage, size_t meta_size_bytes) uint64_t consumer_usage, size_t user_metadata_size) : BASE(BufferHubRPC::kClientPath) { ATRACE_NAME("BufferProducer::BufferProducer"); ALOGD_IF(TRACE, "BufferProducer::BufferProducer: fd=%d name=%s user_id=%d " "group_id=%d width=%u height=%u format=%u producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 " meta_size_bytes=%zu", " consumer_usage=%" PRIx64 " user_metadata_size=%zu", event_fd(), name.c_str(), user_id, group_id, width, height, format, producer_usage, consumer_usage, meta_size_bytes); producer_usage, consumer_usage, user_metadata_size); // (b/37881101) Deprecate producer/consumer usage auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( name, user_id, group_id, width, height, format, (producer_usage | consumer_usage), meta_size_bytes); (producer_usage | consumer_usage), user_metadata_size); if (!status) { ALOGE( "BufferProducer::BufferProducer: Failed to create/get persistent " Loading Loading @@ -260,12 +489,12 @@ BufferProducer::BufferProducer(uint64_t producer_usage, uint64_t consumer_usage, const int width = static_cast<int>(size); const int height = 1; const int format = HAL_PIXEL_FORMAT_BLOB; const size_t meta_size_bytes = 0; const size_t user_metadata_size = 0; // (b/37881101) Deprecate producer/consumer usage auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( width, height, format, (producer_usage | consumer_usage), meta_size_bytes); user_metadata_size); if (!status) { ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s", status.GetErrorMessage().c_str()); Loading Loading @@ -299,12 +528,12 @@ BufferProducer::BufferProducer(const std::string& name, int user_id, const int width = static_cast<int>(size); const int height = 1; const int format = HAL_PIXEL_FORMAT_BLOB; const size_t meta_size_bytes = 0; const size_t user_metadata_size = 0; // (b/37881101) Deprecate producer/consumer usage auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( name, user_id, group_id, width, height, format, (producer_usage | consumer_usage), meta_size_bytes); (producer_usage | consumer_usage), user_metadata_size); if (!status) { ALOGE( "BufferProducer::BufferProducer: Failed to create persistent " Loading Loading @@ -360,28 +589,141 @@ BufferProducer::BufferProducer(LocalChannelHandle channel) } } 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 meta_size_bytes) { 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()), WrapBuffer(meta, meta_size_bytes))); 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(); if (release_fence) *release_fence = status.take().take(); return 0; } int BufferProducer::GainAsync() { 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()); Loading Loading
cmds/atrace/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ cc_binary { "libhidltransport", "liblog", "libutils", "libcutils", "libz", "libbase", ], Loading
libs/vr/libbufferhub/Android.bp +6 −3 Original line number Diff line number Diff line Loading @@ -37,7 +37,8 @@ sharedLibraries = [ "libnativewindow" ] HeaderLibraries = [ headerLibraries = [ "libdvr_headers", "libnativebase_headers", ] Loading @@ -45,12 +46,13 @@ cc_library { srcs: sourceFiles, cflags: [ "-DLOG_TAG=\"libbufferhub\"", "-DTRACE=0" "-DTRACE=0", "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", ], export_include_dirs: localIncludeFiles, static_libs: staticLibraries, shared_libs: sharedLibraries, header_libs: HeaderLibraries, header_libs: headerLibraries, name: "libbufferhub", export_header_lib_headers: [ "libnativebase_headers", Loading @@ -62,6 +64,7 @@ cc_test { srcs: ["bufferhub_tests.cpp"], static_libs: ["libbufferhub"] + staticLibraries, shared_libs: sharedLibraries, header_libs: headerLibraries, name: "bufferhub_tests", }
libs/vr/libbufferhub/buffer_hub_client.cpp +385 −43 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ #include <log/log.h> #include <poll.h> #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include <sys/epoll.h> #include <utils/Trace.h> #include <mutex> Loading @@ -12,9 +12,8 @@ #include "include/private/dvr/bufferhub_rpc.h" using android::pdx::LocalHandle; using android::pdx::LocalChannelHandle; using android::pdx::rpc::WrapBuffer; using android::pdx::LocalHandle; using android::pdx::Status; namespace android { Loading @@ -29,7 +28,11 @@ BufferHubBuffer::BufferHubBuffer(const std::string& endpoint_path) endpoint_path)}, id_(-1) {} BufferHubBuffer::~BufferHubBuffer() {} BufferHubBuffer::~BufferHubBuffer() { if (metadata_header_ != nullptr) { metadata_buffer_.Unlock(); } } Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() { Status<LocalChannelHandle> status = Loading @@ -43,7 +46,7 @@ Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() { int BufferHubBuffer::ImportBuffer() { ATRACE_NAME("BufferHubBuffer::ImportBuffer"); Status<NativeBufferHandle<LocalHandle>> status = Status<BufferDescription<LocalHandle>> status = InvokeRemoteMethod<BufferHubRPC::GetBuffer>(); if (!status) { ALOGE("BufferHubBuffer::ImportBuffer: Failed to get buffer: %s", Loading @@ -54,24 +57,135 @@ int BufferHubBuffer::ImportBuffer() { return -EIO; } auto buffer_handle = status.take(); auto buffer_desc = status.take(); // Stash the buffer id to replace the value in id_. const int new_id = buffer_handle.id(); const int new_id = buffer_desc.id(); // Import the buffer. IonBuffer ion_buffer; ALOGD_IF( TRACE, "BufferHubBuffer::ImportBuffer: id=%d FdCount=%zu IntCount=%zu", buffer_handle.id(), buffer_handle.FdCount(), buffer_handle.IntCount()); ALOGD_IF(TRACE, "BufferHubBuffer::ImportBuffer: id=%d.", buffer_desc.id()); const int ret = buffer_handle.Import(&ion_buffer); if (ret < 0) if (const int ret = buffer_desc.ImportBuffer(&ion_buffer)) return ret; // If the import succeeds, replace the previous buffer and id. // 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; 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; } Loading Loading @@ -131,31 +245,144 @@ std::unique_ptr<BufferConsumer> BufferConsumer::Import( : 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 meta_size_bytes) { size_t user_metadata_size) { ATRACE_NAME("BufferConsumer::Acquire"); LocalFence fence; auto return_value = std::make_pair(std::ref(fence), WrapBuffer(meta, meta_size_bytes)); auto status = InvokeRemoteMethodInPlace<BufferHubRPC::ConsumerAcquire>( &return_value, meta_size_bytes); if (status && ready_fence) *ready_fence = fence.take(); return status ? 0 : -status.error(); 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)); } Loading @@ -168,24 +395,25 @@ int BufferConsumer::SetIgnore(bool ignore) { } BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, uint32_t usage, size_t metadata_size) : BufferProducer(width, height, format, usage, usage, metadata_size) {} uint32_t usage, size_t user_metadata_size) : BufferProducer(width, height, format, usage, usage, user_metadata_size) {} BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, uint64_t producer_usage, uint64_t consumer_usage, size_t metadata_size) 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 " "producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 " metadata_size=%zu", " user_metadata_size=%zu", event_fd(), width, height, format, producer_usage, consumer_usage, metadata_size); user_metadata_size); // (b/37881101) Deprecate producer/consumer usage auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( width, height, format, (producer_usage | consumer_usage), metadata_size); width, height, format, (producer_usage | consumer_usage), user_metadata_size); if (!status) { ALOGE( "BufferProducer::BufferProducer: Failed to create producer buffer: %s", Loading @@ -206,27 +434,28 @@ BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format, BufferProducer::BufferProducer(const std::string& name, int user_id, int group_id, uint32_t width, uint32_t height, uint32_t format, uint32_t usage, size_t meta_size_bytes) size_t user_metadata_size) : BufferProducer(name, user_id, group_id, width, height, format, usage, usage, meta_size_bytes) {} usage, user_metadata_size) {} BufferProducer::BufferProducer(const std::string& name, int user_id, int group_id, uint32_t width, uint32_t height, uint32_t format, uint64_t producer_usage, uint64_t consumer_usage, size_t meta_size_bytes) uint64_t consumer_usage, size_t user_metadata_size) : BASE(BufferHubRPC::kClientPath) { ATRACE_NAME("BufferProducer::BufferProducer"); ALOGD_IF(TRACE, "BufferProducer::BufferProducer: fd=%d name=%s user_id=%d " "group_id=%d width=%u height=%u format=%u producer_usage=%" PRIx64 " consumer_usage=%" PRIx64 " meta_size_bytes=%zu", " consumer_usage=%" PRIx64 " user_metadata_size=%zu", event_fd(), name.c_str(), user_id, group_id, width, height, format, producer_usage, consumer_usage, meta_size_bytes); producer_usage, consumer_usage, user_metadata_size); // (b/37881101) Deprecate producer/consumer usage auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( name, user_id, group_id, width, height, format, (producer_usage | consumer_usage), meta_size_bytes); (producer_usage | consumer_usage), user_metadata_size); if (!status) { ALOGE( "BufferProducer::BufferProducer: Failed to create/get persistent " Loading Loading @@ -260,12 +489,12 @@ BufferProducer::BufferProducer(uint64_t producer_usage, uint64_t consumer_usage, const int width = static_cast<int>(size); const int height = 1; const int format = HAL_PIXEL_FORMAT_BLOB; const size_t meta_size_bytes = 0; const size_t user_metadata_size = 0; // (b/37881101) Deprecate producer/consumer usage auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( width, height, format, (producer_usage | consumer_usage), meta_size_bytes); user_metadata_size); if (!status) { ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s", status.GetErrorMessage().c_str()); Loading Loading @@ -299,12 +528,12 @@ BufferProducer::BufferProducer(const std::string& name, int user_id, const int width = static_cast<int>(size); const int height = 1; const int format = HAL_PIXEL_FORMAT_BLOB; const size_t meta_size_bytes = 0; const size_t user_metadata_size = 0; // (b/37881101) Deprecate producer/consumer usage auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>( name, user_id, group_id, width, height, format, (producer_usage | consumer_usage), meta_size_bytes); (producer_usage | consumer_usage), user_metadata_size); if (!status) { ALOGE( "BufferProducer::BufferProducer: Failed to create persistent " Loading Loading @@ -360,28 +589,141 @@ BufferProducer::BufferProducer(LocalChannelHandle channel) } } 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 meta_size_bytes) { 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()), WrapBuffer(meta, meta_size_bytes))); 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(); if (release_fence) *release_fence = status.take().take(); return 0; } int BufferProducer::GainAsync() { 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()); Loading