| Jiwen 'Steve' Cai | c6fcf2f | 2018-09-27 23:34:45 -0700 | [diff] [blame] | 1 | #include <private/dvr/producer_buffer.h> | 
 | 2 |  | 
 | 3 | using android::pdx::LocalChannelHandle; | 
 | 4 | using android::pdx::LocalHandle; | 
 | 5 | using android::pdx::Status; | 
 | 6 |  | 
 | 7 | namespace android { | 
 | 8 | namespace dvr { | 
 | 9 |  | 
 | 10 | ProducerBuffer::ProducerBuffer(uint32_t width, uint32_t height, uint32_t format, | 
 | 11 |                                uint64_t usage, size_t user_metadata_size) | 
 | 12 |     : BASE(BufferHubRPC::kClientPath) { | 
 | 13 |   ATRACE_NAME("ProducerBuffer::ProducerBuffer"); | 
 | 14 |   ALOGD_IF(TRACE, | 
 | 15 |            "ProducerBuffer::ProducerBuffer: fd=%d width=%u height=%u format=%u " | 
 | 16 |            "usage=%" PRIx64 " user_metadata_size=%zu", | 
 | 17 |            event_fd(), width, height, format, usage, user_metadata_size); | 
 | 18 |  | 
 | 19 |   auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( | 
 | 20 |       width, height, format, usage, user_metadata_size); | 
 | 21 |   if (!status) { | 
 | 22 |     ALOGE( | 
 | 23 |         "ProducerBuffer::ProducerBuffer: Failed to create producer buffer: %s", | 
 | 24 |         status.GetErrorMessage().c_str()); | 
 | 25 |     Close(-status.error()); | 
 | 26 |     return; | 
 | 27 |   } | 
 | 28 |  | 
 | 29 |   const int ret = ImportBuffer(); | 
 | 30 |   if (ret < 0) { | 
 | 31 |     ALOGE( | 
 | 32 |         "ProducerBuffer::ProducerBuffer: Failed to import producer buffer: %s", | 
 | 33 |         strerror(-ret)); | 
 | 34 |     Close(ret); | 
 | 35 |   } | 
 | 36 | } | 
 | 37 |  | 
 | 38 | ProducerBuffer::ProducerBuffer(uint64_t usage, size_t size) | 
 | 39 |     : BASE(BufferHubRPC::kClientPath) { | 
 | 40 |   ATRACE_NAME("ProducerBuffer::ProducerBuffer"); | 
 | 41 |   ALOGD_IF(TRACE, "ProducerBuffer::ProducerBuffer: usage=%" PRIx64 " size=%zu", | 
 | 42 |            usage, size); | 
 | 43 |   const int width = static_cast<int>(size); | 
 | 44 |   const int height = 1; | 
 | 45 |   const int format = HAL_PIXEL_FORMAT_BLOB; | 
 | 46 |   const size_t user_metadata_size = 0; | 
 | 47 |  | 
 | 48 |   auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>( | 
 | 49 |       width, height, format, usage, user_metadata_size); | 
 | 50 |   if (!status) { | 
 | 51 |     ALOGE("ProducerBuffer::ProducerBuffer: Failed to create blob: %s", | 
 | 52 |           status.GetErrorMessage().c_str()); | 
 | 53 |     Close(-status.error()); | 
 | 54 |     return; | 
 | 55 |   } | 
 | 56 |  | 
 | 57 |   const int ret = ImportBuffer(); | 
 | 58 |   if (ret < 0) { | 
 | 59 |     ALOGE( | 
 | 60 |         "ProducerBuffer::ProducerBuffer: Failed to import producer buffer: %s", | 
 | 61 |         strerror(-ret)); | 
 | 62 |     Close(ret); | 
 | 63 |   } | 
 | 64 | } | 
 | 65 |  | 
 | 66 | ProducerBuffer::ProducerBuffer(LocalChannelHandle channel) | 
 | 67 |     : BASE(std::move(channel)) { | 
 | 68 |   const int ret = ImportBuffer(); | 
 | 69 |   if (ret < 0) { | 
 | 70 |     ALOGE( | 
 | 71 |         "ProducerBuffer::ProducerBuffer: Failed to import producer buffer: %s", | 
 | 72 |         strerror(-ret)); | 
 | 73 |     Close(ret); | 
 | 74 |   } | 
 | 75 | } | 
 | 76 |  | 
 | 77 | int ProducerBuffer::LocalPost(const DvrNativeBufferMetadata* meta, | 
 | 78 |                               const LocalHandle& ready_fence) { | 
 | 79 |   if (const int error = CheckMetadata(meta->user_metadata_size)) | 
 | 80 |     return error; | 
 | 81 |  | 
 | 82 |   // Check invalid state transition. | 
 | 83 |   uint64_t buffer_state = buffer_state_->load(); | 
 | 84 |   if (!BufferHubDefs::IsBufferGained(buffer_state)) { | 
 | 85 |     ALOGE("ProducerBuffer::LocalPost: not gained, id=%d state=%" PRIx64 ".", | 
 | 86 |           id(), buffer_state); | 
 | 87 |     return -EBUSY; | 
 | 88 |   } | 
 | 89 |  | 
 | 90 |   // Copy the canonical metadata. | 
 | 91 |   void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata); | 
 | 92 |   memcpy(metadata_ptr, meta, sizeof(DvrNativeBufferMetadata)); | 
 | 93 |   // Copy extra user requested metadata. | 
 | 94 |   if (meta->user_metadata_ptr && meta->user_metadata_size) { | 
 | 95 |     void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr); | 
 | 96 |     memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size); | 
 | 97 |   } | 
 | 98 |  | 
 | 99 |   // Send out the acquire fence through the shared epoll fd. Note that during | 
 | 100 |   // posting no consumer is not expected to be polling on the fence. | 
 | 101 |   if (const int error = UpdateSharedFence(ready_fence, shared_acquire_fence_)) | 
 | 102 |     return error; | 
 | 103 |  | 
 | 104 |   // Set the producer bit atomically to transit into posted state. | 
 | 105 |   BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, | 
 | 106 |                                    BufferHubDefs::kProducerStateBit); | 
 | 107 |   return 0; | 
 | 108 | } | 
 | 109 |  | 
 | 110 | int ProducerBuffer::Post(const LocalHandle& ready_fence, const void* meta, | 
 | 111 |                          size_t user_metadata_size) { | 
 | 112 |   ATRACE_NAME("ProducerBuffer::Post"); | 
 | 113 |  | 
 | 114 |   // Populate cononical metadata for posting. | 
 | 115 |   DvrNativeBufferMetadata canonical_meta; | 
 | 116 |   canonical_meta.user_metadata_ptr = reinterpret_cast<uint64_t>(meta); | 
 | 117 |   canonical_meta.user_metadata_size = user_metadata_size; | 
 | 118 |  | 
 | 119 |   if (const int error = LocalPost(&canonical_meta, ready_fence)) | 
 | 120 |     return error; | 
 | 121 |  | 
 | 122 |   return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ProducerPost>( | 
 | 123 |       BorrowedFence(ready_fence.Borrow()))); | 
 | 124 | } | 
 | 125 |  | 
 | 126 | int ProducerBuffer::PostAsync(const DvrNativeBufferMetadata* meta, | 
 | 127 |                               const LocalHandle& ready_fence) { | 
 | 128 |   ATRACE_NAME("ProducerBuffer::PostAsync"); | 
 | 129 |  | 
 | 130 |   if (const int error = LocalPost(meta, ready_fence)) | 
 | 131 |     return error; | 
 | 132 |  | 
 | 133 |   return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerPost::Opcode)); | 
 | 134 | } | 
 | 135 |  | 
 | 136 | int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta, | 
 | 137 |                               LocalHandle* out_fence) { | 
 | 138 |   uint64_t buffer_state = buffer_state_->load(); | 
 | 139 |   ALOGD_IF(TRACE, "ProducerBuffer::LocalGain: buffer=%d, state=%" PRIx64 ".", | 
 | 140 |            id(), buffer_state); | 
 | 141 |  | 
 | 142 |   if (!out_meta) | 
 | 143 |     return -EINVAL; | 
 | 144 |  | 
 | 145 |   if (!BufferHubDefs::IsBufferReleased(buffer_state)) { | 
 | 146 |     if (BufferHubDefs::IsBufferGained(buffer_state)) { | 
 | 147 |       // We don't want to log error when gaining a newly allocated | 
 | 148 |       // buffer. | 
 | 149 |       ALOGI("ProducerBuffer::LocalGain: already gained id=%d.", id()); | 
 | 150 |       return -EALREADY; | 
 | 151 |     } | 
 | 152 |     ALOGE("ProducerBuffer::LocalGain: not released id=%d state=%" PRIx64 ".", | 
 | 153 |           id(), buffer_state); | 
 | 154 |     return -EBUSY; | 
 | 155 |   } | 
 | 156 |  | 
 | 157 |   // Canonical metadata is undefined on Gain. Except for user_metadata and | 
 | 158 |   // release_fence_mask. Fill in the user_metadata_ptr in address space of the | 
 | 159 |   // local process. | 
 | 160 |   if (metadata_header_->metadata.user_metadata_size && user_metadata_ptr_) { | 
 | 161 |     out_meta->user_metadata_size = | 
 | 162 |         metadata_header_->metadata.user_metadata_size; | 
 | 163 |     out_meta->user_metadata_ptr = | 
 | 164 |         reinterpret_cast<uint64_t>(user_metadata_ptr_); | 
 | 165 |   } else { | 
 | 166 |     out_meta->user_metadata_size = 0; | 
 | 167 |     out_meta->user_metadata_ptr = 0; | 
 | 168 |   } | 
 | 169 |  | 
 | 170 |   uint64_t fence_state = fence_state_->load(); | 
 | 171 |   // If there is an release fence from consumer, we need to return it. | 
 | 172 |   if (fence_state & BufferHubDefs::kConsumerStateMask) { | 
 | 173 |     *out_fence = shared_release_fence_.Duplicate(); | 
 | 174 |     out_meta->release_fence_mask = | 
 | 175 |         fence_state & BufferHubDefs::kConsumerStateMask; | 
 | 176 |   } | 
 | 177 |  | 
 | 178 |   // Clear out all bits and the buffer is now back to gained state. | 
 | 179 |   buffer_state_->store(0ULL); | 
 | 180 |   return 0; | 
 | 181 | } | 
 | 182 |  | 
 | 183 | int ProducerBuffer::Gain(LocalHandle* release_fence) { | 
 | 184 |   ATRACE_NAME("ProducerBuffer::Gain"); | 
 | 185 |  | 
 | 186 |   DvrNativeBufferMetadata meta; | 
 | 187 |   if (const int error = LocalGain(&meta, release_fence)) | 
 | 188 |     return error; | 
 | 189 |  | 
 | 190 |   auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>(); | 
 | 191 |   if (!status) | 
 | 192 |     return -status.error(); | 
 | 193 |   return 0; | 
 | 194 | } | 
 | 195 |  | 
 | 196 | int ProducerBuffer::GainAsync(DvrNativeBufferMetadata* out_meta, | 
 | 197 |                               LocalHandle* release_fence) { | 
 | 198 |   ATRACE_NAME("ProducerBuffer::GainAsync"); | 
 | 199 |  | 
 | 200 |   if (const int error = LocalGain(out_meta, release_fence)) | 
 | 201 |     return error; | 
 | 202 |  | 
 | 203 |   return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode)); | 
 | 204 | } | 
 | 205 |  | 
 | 206 | int ProducerBuffer::GainAsync() { | 
 | 207 |   DvrNativeBufferMetadata meta; | 
 | 208 |   LocalHandle fence; | 
 | 209 |   return GainAsync(&meta, &fence); | 
 | 210 | } | 
 | 211 |  | 
 | 212 | std::unique_ptr<ProducerBuffer> ProducerBuffer::Import( | 
 | 213 |     LocalChannelHandle channel) { | 
 | 214 |   ALOGD_IF(TRACE, "ProducerBuffer::Import: channel=%d", channel.value()); | 
 | 215 |   return ProducerBuffer::Create(std::move(channel)); | 
 | 216 | } | 
 | 217 |  | 
 | 218 | std::unique_ptr<ProducerBuffer> ProducerBuffer::Import( | 
 | 219 |     Status<LocalChannelHandle> status) { | 
 | 220 |   return Import(status ? status.take() | 
 | 221 |                        : LocalChannelHandle{nullptr, -status.error()}); | 
 | 222 | } | 
 | 223 |  | 
 | 224 | Status<LocalChannelHandle> ProducerBuffer::Detach() { | 
 | 225 |   uint64_t buffer_state = buffer_state_->load(); | 
 | 226 |   if (!BufferHubDefs::IsBufferGained(buffer_state)) { | 
 | 227 |     // Can only detach a ProducerBuffer when it's in gained state. | 
 | 228 |     ALOGW("ProducerBuffer::Detach: The buffer (id=%d, state=0x%" PRIx64 | 
 | 229 |           ") is not in gained state.", | 
 | 230 |           id(), buffer_state); | 
 | 231 |     return {}; | 
 | 232 |   } | 
 | 233 |  | 
 | 234 |   Status<LocalChannelHandle> status = | 
 | 235 |       InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>(); | 
 | 236 |   ALOGE_IF(!status, | 
 | 237 |            "ProducerBuffer::Detach: Failed to detach buffer (id=%d): %s.", id(), | 
 | 238 |            status.GetErrorMessage().c_str()); | 
 | 239 |   return status; | 
 | 240 | } | 
 | 241 |  | 
 | 242 | }  // namespace dvr | 
 | 243 | }  // namespace android |