blob: c4f1a3b486ed536411850611f9272a671a309493 [file] [log] [blame]
Jiwen 'Steve' Caic6fcf2f2018-09-27 23:34:45 -07001#include <private/dvr/producer_buffer.h>
2
3using android::pdx::LocalChannelHandle;
4using android::pdx::LocalHandle;
5using android::pdx::Status;
6
7namespace android {
8namespace dvr {
9
10ProducerBuffer::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
38ProducerBuffer::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
66ProducerBuffer::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
77int 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
110int 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
126int 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
136int 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
183int 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
196int 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
206int ProducerBuffer::GainAsync() {
207 DvrNativeBufferMetadata meta;
208 LocalHandle fence;
209 return GainAsync(&meta, &fence);
210}
211
212std::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
218std::unique_ptr<ProducerBuffer> ProducerBuffer::Import(
219 Status<LocalChannelHandle> status) {
220 return Import(status ? status.take()
221 : LocalChannelHandle{nullptr, -status.error()});
222}
223
224Status<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