• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ProducerBuffer(uint32_t width,uint32_t height,uint32_t format,uint64_t usage,size_t user_metadata_size)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 
ProducerBuffer(uint64_t usage,size_t size)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 
ProducerBuffer(LocalChannelHandle channel)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 
LocalPost(const DvrNativeBufferMetadata * meta,const LocalHandle & ready_fence)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   // The buffer can be posted iff the buffer state for this client is gained.
83   uint32_t current_buffer_state =
84       buffer_state_->load(std::memory_order_acquire);
85   if (!BufferHubDefs::isClientGained(current_buffer_state,
86                                      client_state_mask())) {
87     ALOGE("%s: not gained, id=%d state=%" PRIx32 ".", __FUNCTION__, id(),
88           current_buffer_state);
89     return -EBUSY;
90   }
91 
92   // Set the producer client buffer state to released, that of all other clients
93   // (both existing and non-existing clients) to posted.
94   uint32_t updated_buffer_state =
95       (~client_state_mask()) & BufferHubDefs::kHighBitsMask;
96   while (!buffer_state_->compare_exchange_weak(
97       current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
98       std::memory_order_acquire)) {
99     if (!BufferHubDefs::isClientGained(current_buffer_state,
100                                        client_state_mask())) {
101       ALOGE(
102           "%s: Failed to post the buffer. The buffer is no longer gained, "
103           "id=%d state=%" PRIx32 ".",
104           __FUNCTION__, id(), current_buffer_state);
105       return -EBUSY;
106     }
107   }
108 
109   // Copy the canonical metadata.
110   void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
111   memcpy(metadata_ptr, meta, sizeof(DvrNativeBufferMetadata));
112   // Copy extra user requested metadata.
113   if (meta->user_metadata_ptr && meta->user_metadata_size) {
114     void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
115     memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
116   }
117 
118   // Send out the acquire fence through the shared epoll fd. Note that during
119   // posting no consumer is not expected to be polling on the fence.
120   if (const int error = UpdateSharedFence(ready_fence, shared_acquire_fence_))
121     return error;
122 
123   return 0;
124 }
125 
Post(const LocalHandle & ready_fence,const void * meta,size_t user_metadata_size)126 int ProducerBuffer::Post(const LocalHandle& ready_fence, const void* meta,
127                          size_t user_metadata_size) {
128   ATRACE_NAME("ProducerBuffer::Post");
129 
130   // Populate cononical metadata for posting.
131   DvrNativeBufferMetadata canonical_meta;
132   canonical_meta.user_metadata_ptr = reinterpret_cast<uint64_t>(meta);
133   canonical_meta.user_metadata_size = user_metadata_size;
134 
135   if (const int error = LocalPost(&canonical_meta, ready_fence))
136     return error;
137 
138   return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ProducerPost>(
139       BorrowedFence(ready_fence.Borrow())));
140 }
141 
PostAsync(const DvrNativeBufferMetadata * meta,const LocalHandle & ready_fence)142 int ProducerBuffer::PostAsync(const DvrNativeBufferMetadata* meta,
143                               const LocalHandle& ready_fence) {
144   ATRACE_NAME("ProducerBuffer::PostAsync");
145 
146   if (const int error = LocalPost(meta, ready_fence))
147     return error;
148 
149   return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerPost::Opcode));
150 }
151 
LocalGain(DvrNativeBufferMetadata * out_meta,LocalHandle * out_fence,bool gain_posted_buffer)152 int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta,
153                               LocalHandle* out_fence, bool gain_posted_buffer) {
154   if (!out_meta)
155     return -EINVAL;
156 
157   uint32_t current_buffer_state =
158       buffer_state_->load(std::memory_order_acquire);
159   ALOGD_IF(TRACE, "%s: buffer=%d, state=%" PRIx32 ".", __FUNCTION__, id(),
160            current_buffer_state);
161 
162   if (BufferHubDefs::isClientGained(current_buffer_state,
163                                     client_state_mask())) {
164     ALOGV("%s: already gained id=%d.", __FUNCTION__, id());
165     return 0;
166   }
167   if (BufferHubDefs::isAnyClientAcquired(current_buffer_state) ||
168       BufferHubDefs::isAnyClientGained(current_buffer_state) ||
169       (BufferHubDefs::isAnyClientPosted(
170            current_buffer_state &
171            active_clients_bit_mask_->load(std::memory_order_acquire)) &&
172        !gain_posted_buffer)) {
173     ALOGE("%s: not released id=%d state=%" PRIx32 ".", __FUNCTION__, id(),
174           current_buffer_state);
175     return -EBUSY;
176   }
177   // Change the buffer state to gained state.
178   uint32_t updated_buffer_state = client_state_mask();
179   while (!buffer_state_->compare_exchange_weak(
180       current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
181       std::memory_order_acquire)) {
182     if (BufferHubDefs::isAnyClientAcquired(current_buffer_state) ||
183         BufferHubDefs::isAnyClientGained(current_buffer_state) ||
184         (BufferHubDefs::isAnyClientPosted(
185              current_buffer_state &
186              active_clients_bit_mask_->load(std::memory_order_acquire)) &&
187          !gain_posted_buffer)) {
188       ALOGE(
189           "%s: Failed to gain the buffer. The buffer is no longer released. "
190           "id=%d state=%" PRIx32 ".",
191           __FUNCTION__, id(), current_buffer_state);
192       return -EBUSY;
193     }
194   }
195 
196   // Canonical metadata is undefined on Gain. Except for user_metadata and
197   // release_fence_mask. Fill in the user_metadata_ptr in address space of the
198   // local process.
199   if (metadata_header_->metadata.user_metadata_size && user_metadata_ptr_) {
200     out_meta->user_metadata_size =
201         metadata_header_->metadata.user_metadata_size;
202     out_meta->user_metadata_ptr =
203         reinterpret_cast<uint64_t>(user_metadata_ptr_);
204   } else {
205     out_meta->user_metadata_size = 0;
206     out_meta->user_metadata_ptr = 0;
207   }
208 
209   uint32_t current_fence_state = fence_state_->load(std::memory_order_acquire);
210   uint32_t current_active_clients_bit_mask =
211       active_clients_bit_mask_->load(std::memory_order_acquire);
212   // If there are release fence(s) from consumer(s), we need to return it to the
213   // consumer(s).
214   // TODO(b/112007999) add an atomic variable in metadata header in shared
215   // memory to indicate which client is the last producer of the buffer.
216   // Currently, assume the first client is the only producer to the buffer.
217   if (current_fence_state & current_active_clients_bit_mask &
218       (~BufferHubDefs::kFirstClientBitMask)) {
219     *out_fence = shared_release_fence_.Duplicate();
220     out_meta->release_fence_mask = current_fence_state &
221                                    current_active_clients_bit_mask &
222                                    (~BufferHubDefs::kFirstClientBitMask);
223   }
224 
225   return 0;
226 }
227 
Gain(LocalHandle * release_fence,bool gain_posted_buffer)228 int ProducerBuffer::Gain(LocalHandle* release_fence, bool gain_posted_buffer) {
229   ATRACE_NAME("ProducerBuffer::Gain");
230 
231   DvrNativeBufferMetadata meta;
232   if (const int error = LocalGain(&meta, release_fence, gain_posted_buffer))
233     return error;
234 
235   auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>();
236   if (!status)
237     return -status.error();
238   return 0;
239 }
240 
GainAsync(DvrNativeBufferMetadata * out_meta,LocalHandle * release_fence,bool gain_posted_buffer)241 int ProducerBuffer::GainAsync(DvrNativeBufferMetadata* out_meta,
242                               LocalHandle* release_fence,
243                               bool gain_posted_buffer) {
244   ATRACE_NAME("ProducerBuffer::GainAsync");
245 
246   if (const int error = LocalGain(out_meta, release_fence, gain_posted_buffer))
247     return error;
248 
249   return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode));
250 }
251 
GainAsync()252 int ProducerBuffer::GainAsync() {
253   DvrNativeBufferMetadata meta;
254   LocalHandle fence;
255   return GainAsync(&meta, &fence);
256 }
257 
Import(LocalChannelHandle channel)258 std::unique_ptr<ProducerBuffer> ProducerBuffer::Import(
259     LocalChannelHandle channel) {
260   ALOGD_IF(TRACE, "ProducerBuffer::Import: channel=%d", channel.value());
261   return ProducerBuffer::Create(std::move(channel));
262 }
263 
Import(Status<LocalChannelHandle> status)264 std::unique_ptr<ProducerBuffer> ProducerBuffer::Import(
265     Status<LocalChannelHandle> status) {
266   return Import(status ? status.take()
267                        : LocalChannelHandle{nullptr, -status.error()});
268 }
269 
Detach()270 Status<LocalChannelHandle> ProducerBuffer::Detach() {
271   // TODO(b/112338294) remove after migrate producer buffer to binder
272   ALOGW("ProducerBuffer::Detach: not supported operation during migration");
273   return {};
274 
275   // TODO(b/112338294) Keep here for reference. Remove it after new logic is
276   // written.
277   /* uint32_t buffer_state = buffer_state_->load(std::memory_order_acquire);
278   if (!BufferHubDefs::isClientGained(
279       buffer_state, BufferHubDefs::kFirstClientStateMask)) {
280     // Can only detach a ProducerBuffer when it's in gained state.
281     ALOGW("ProducerBuffer::Detach: The buffer (id=%d, state=0x%" PRIx32
282           ") is not in gained state.",
283           id(), buffer_state);
284     return {};
285   }
286 
287   Status<LocalChannelHandle> status =
288       InvokeRemoteMethod<BufferHubRPC::ProducerBufferDetach>();
289   ALOGE_IF(!status,
290            "ProducerBuffer::Detach: Failed to detach buffer (id=%d): %s.", id(),
291            status.GetErrorMessage().c_str());
292   return status; */
293 }
294 
295 }  // namespace dvr
296 }  // namespace android
297