1 /*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef CODEC2_COMMON_BUFFER_TYPES_H
18 #define CODEC2_COMMON_BUFFER_TYPES_H
19
20 #ifndef LOG_TAG
21 #define LOG_TAG "Codec2-BufferTypes"
22 #endif
23 #include <android-base/logging.h>
24
25 #include <codec2/common/BufferPoolSender.h>
26 #include <codec2/common/ParamTypes.h>
27 #include <media/stagefright/foundation/AUtils.h>
28
29 #include <C2AllocatorIon.h>
30 #include <C2AllocatorGralloc.h>
31 #include <C2BlockInternal.h>
32 #include <C2Buffer.h>
33 #include <C2Component.h>
34 #include <C2FenceFactory.h>
35 #include <C2Param.h>
36 #include <C2ParamDef.h>
37 #include <C2PlatformSupport.h>
38 #include <C2Work.h>
39
40 #include <algorithm>
41 #include <functional>
42 #include <iomanip>
43 #include <map>
44
45 namespace android {
46
47 // Types of metadata for Blocks.
48 struct C2Hal_Range {
49 uint32_t offset;
50 uint32_t length; // Do not use "size" because the name collides with C2Info::size().
51 };
52 typedef C2GlobalParam<C2Info, C2Hal_Range, 0> C2Hal_RangeInfo;
53
54 struct C2Hal_Rect {
55 uint32_t left;
56 uint32_t top;
57 uint32_t width;
58 uint32_t height;
59 };
60 typedef C2GlobalParam<C2Info, C2Hal_Rect, 1> C2Hal_RectInfo;
61
62 // Note: The handle is not cloned.
63 template <typename BaseBlock>
64 void SetHandle(BaseBlock *baseBlock, const C2Handle *handle);
65
66 template <typename BaseBlock>
67 void SetAHardwareBuffer(BaseBlock *baseBlock, AHardwareBuffer *pBuf);
68
69 template <typename BufferPoolTypes, typename BaseBlock>
70 void SetPooledBlock(
71 BaseBlock *baseBlock,
72 const typename BufferPoolTypes::BufferStatusMessage &pooledBlock);
73
74 template <typename BufferPoolTypes>
75 bool GetBufferPoolData(
76 const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
77 std::shared_ptr<typename BufferPoolTypes::BufferPoolData> *bpData);
78
79 // Find or add a HAL BaseBlock object from a given C2Handle* to a list and an
80 // associated map.
81 // Note: The handle is not cloned.
82 template <typename BaseBlock>
_addBaseBlock(uint32_t * index,const C2Handle * handle,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)83 bool _addBaseBlock(
84 uint32_t* index,
85 const C2Handle* handle,
86 std::list<BaseBlock>* baseBlocks,
87 std::map<const void*, uint32_t>* baseBlockIndices) {
88 if (!handle) {
89 LOG(ERROR) << "addBaseBlock called on a null C2Handle.";
90 return false;
91 }
92 auto it = baseBlockIndices->find(handle);
93 if (it != baseBlockIndices->end()) {
94 *index = it->second;
95 } else {
96 *index = baseBlocks->size();
97 baseBlockIndices->emplace(handle, *index);
98 baseBlocks->emplace_back();
99
100 BaseBlock &dBaseBlock = baseBlocks->back();
101 SetHandle(&dBaseBlock, handle);
102 }
103 return true;
104 }
105
106 // Find or add a HAL BaseBlock object from a given AHardwareBuffer* to a list and an
107 // associated map.
108 template <typename BaseBlock>
_addBaseBlock(uint32_t * index,AHardwareBuffer * pBuf,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)109 bool _addBaseBlock(
110 uint32_t* index,
111 AHardwareBuffer* pBuf,
112 std::list<BaseBlock>* baseBlocks,
113 std::map<const void*, uint32_t>* baseBlockIndices) {
114 if (!pBuf) {
115 LOG(ERROR) << "addBaseBlock called on a null AHardwareBuffer.";
116 }
117 auto it = baseBlockIndices->find(pBuf);
118 if (it != baseBlockIndices->end()) {
119 *index = it->second;
120 } else {
121 *index = baseBlocks->size();
122 baseBlockIndices->emplace(pBuf, *index);
123 baseBlocks->emplace_back();
124
125 BaseBlock &dBaseBlock = baseBlocks->back();
126 SetAHardwareBuffer(&dBaseBlock, pBuf);
127 }
128 return true;
129 }
130
131 // Find or add a hidl BaseBlock object from a given BufferPoolData to a list and
132 // an associated map.
133 template <typename BufferPoolTypes, typename BaseBlock>
_addBaseBlock(uint32_t * index,const std::shared_ptr<typename BufferPoolTypes::BufferPoolData> & bpData,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)134 bool _addBaseBlock(
135 uint32_t* index,
136 const std::shared_ptr<typename BufferPoolTypes::BufferPoolData> &bpData,
137 BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
138 std::list<BaseBlock>* baseBlocks,
139 std::map<const void*, uint32_t>* baseBlockIndices) {
140 if (!bpData) {
141 LOG(ERROR) << "addBaseBlock called on a null BufferPoolData.";
142 return false;
143 }
144 auto it = baseBlockIndices->find(bpData.get());
145 if (it != baseBlockIndices->end()) {
146 *index = it->second;
147 } else {
148 *index = baseBlocks->size();
149 baseBlockIndices->emplace(bpData.get(), *index);
150 baseBlocks->emplace_back();
151
152 BaseBlock &dBaseBlock = baseBlocks->back();
153
154 if (bufferPoolSender) {
155 typename BufferPoolTypes::BufferStatusMessage pooledBlock;
156 typename BufferPoolTypes::BufferPoolStatus bpStatus =
157 bufferPoolSender->send(bpData, &pooledBlock);
158
159 if (bpStatus != BufferPoolTypes::ResultStatus::OK) {
160 LOG(ERROR) << "Failed to send buffer with BufferPool. Error: "
161 << static_cast<int32_t>(bpStatus)
162 << ".";
163 return false;
164 }
165 SetPooledBlock<BufferPoolTypes>(&dBaseBlock, pooledBlock);
166 }
167 }
168 return true;
169 }
170
171 template <typename BufferPoolTypes, typename BaseBlock>
addBaseBlock(uint32_t * index,const C2Handle * handle,const std::shared_ptr<const _C2BlockPoolData> & blockPoolData,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)172 bool addBaseBlock(
173 uint32_t* index,
174 const C2Handle* handle,
175 const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
176 BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
177 std::list<BaseBlock>* baseBlocks,
178 std::map<const void*, uint32_t>* baseBlockIndices) {
179 if (!blockPoolData) {
180 // No BufferPoolData ==> NATIVE block.
181 return _addBaseBlock(
182 index, handle,
183 baseBlocks, baseBlockIndices);
184 }
185 switch (blockPoolData->getType()) {
186 case _C2BlockPoolData::TYPE_BUFFERPOOL:
187 case _C2BlockPoolData::TYPE_BUFFERPOOL2: {
188 // BufferPoolData
189 std::shared_ptr<typename BufferPoolTypes::BufferPoolData> bpData;
190 if (!GetBufferPoolData<BufferPoolTypes>(blockPoolData, &bpData) || !bpData) {
191 LOG(ERROR) << "BufferPoolData unavailable in a block.";
192 return false;
193 }
194 return _addBaseBlock(
195 index, bpData,
196 bufferPoolSender, baseBlocks, baseBlockIndices);
197 }
198 case _C2BlockPoolData::TYPE_BUFFERQUEUE: {
199 uint32_t gen;
200 uint64_t bqId;
201 int32_t bqSlot;
202 // Update handle if migration happened.
203 if (_C2BlockFactory::GetBufferQueueData(
204 blockPoolData, &gen, &bqId, &bqSlot)) {
205 android::MigrateNativeCodec2GrallocHandle(
206 const_cast<native_handle_t*>(handle), gen, bqId, bqSlot);
207 }
208 return _addBaseBlock(
209 index, handle,
210 baseBlocks, baseBlockIndices);
211 }
212 case _C2BlockPoolData::TYPE_AHWBUFFER: {
213 AHardwareBuffer *pBuf;
214 if (!_C2BlockFactory::GetAHardwareBuffer(blockPoolData, &pBuf)) {
215 LOG(ERROR) << "AHardwareBuffer unavailable in a block.";
216 return false;
217 }
218 return _addBaseBlock(
219 index, pBuf,
220 baseBlocks, baseBlockIndices);
221 }
222 default:
223 LOG(ERROR) << "Unknown C2BlockPoolData type.";
224 return false;
225 }
226 }
227
228 // C2Fence -> Handle
229 // Note: File descriptors are not duplicated. The original file descriptor must
230 // not be closed before the transaction is complete.
231 template <typename Handle>
objcpy(Handle * d,const C2Fence & s)232 bool objcpy(Handle* d, const C2Fence& s) {
233 d->setTo(nullptr);
234 native_handle_t* handle = _C2FenceFactory::CreateNativeHandle(s);
235 if (handle) {
236 d->setTo(handle, true /* owns */);
237 // } else if (!s.ready()) {
238 // // TODO: we should wait for unmarshallable fences but this may not be
239 // // the best place for it. We can safely ignore here as at this time
240 // // all fences used here are marshallable.
241 }
242 return true;
243 }
244
245 // C2ConstLinearBlock -> Block
246 // Note: Native handles are not duplicated. The original handles must not be
247 // closed before the transaction is complete.
248 template <typename Block, typename BufferPoolTypes, typename BaseBlock>
objcpy(Block * d,const C2ConstLinearBlock & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)249 bool objcpy(Block* d, const C2ConstLinearBlock& s,
250 BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
251 std::list<BaseBlock>* baseBlocks,
252 std::map<const void*, uint32_t>* baseBlockIndices) {
253 std::shared_ptr<const _C2BlockPoolData> bpData =
254 _C2BlockFactory::GetLinearBlockPoolData(s);
255 if (!addBaseBlock((uint32_t *)&d->index, s.handle(), bpData,
256 bufferPoolSender, baseBlocks, baseBlockIndices)) {
257 LOG(ERROR) << "Invalid block data in C2ConstLinearBlock.";
258 return false;
259 }
260
261 // Create the metadata.
262 C2Hal_RangeInfo dRangeInfo;
263 dRangeInfo.offset = static_cast<uint32_t>(s.offset());
264 dRangeInfo.length = static_cast<uint32_t>(s.size());
265 if (!_createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRangeInfo })) {
266 LOG(ERROR) << "Invalid range info in C2ConstLinearBlock.";
267 return false;
268 }
269
270 // Copy the fence
271 if (!objcpy(&d->fence, s.fence())) {
272 LOG(ERROR) << "Invalid C2ConstLinearBlock::fence.";
273 return false;
274 }
275 return true;
276 }
277
278 // C2ConstGraphicBlock -> Block
279 // Note: Native handles are not duplicated. The original handles must not be
280 // closed before the transaction is complete.
281 template <typename Block, typename BufferPoolTypes, typename BaseBlock>
objcpy(Block * d,const C2ConstGraphicBlock & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)282 bool objcpy(Block* d, const C2ConstGraphicBlock& s,
283 BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
284 std::list<BaseBlock>* baseBlocks,
285 std::map<const void*, uint32_t>* baseBlockIndices) {
286 std::shared_ptr<const _C2BlockPoolData> bpData =
287 _C2BlockFactory::GetGraphicBlockPoolData(s);
288 if (!addBaseBlock((uint32_t *)&d->index, s.handle(), bpData,
289 bufferPoolSender, baseBlocks, baseBlockIndices)) {
290 LOG(ERROR) << "Invalid block data in C2ConstGraphicBlock.";
291 return false;
292 }
293
294 // Create the metadata.
295 C2Hal_RectInfo dRectInfo;
296 C2Rect sRect = s.crop();
297 dRectInfo.left = static_cast<uint32_t>(sRect.left);
298 dRectInfo.top = static_cast<uint32_t>(sRect.top);
299 dRectInfo.width = static_cast<uint32_t>(sRect.width);
300 dRectInfo.height = static_cast<uint32_t>(sRect.height);
301 if (!_createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRectInfo })) {
302 LOG(ERROR) << "Invalid rect info in C2ConstGraphicBlock.";
303 return false;
304 }
305
306 // Copy the fence
307 if (!objcpy(&d->fence, s.fence())) {
308 LOG(ERROR) << "Invalid C2ConstGraphicBlock::fence.";
309 return false;
310 }
311 return true;
312 }
313
314 // C2BufferData -> Buffer
315 // This function only fills in d->blocks.
316 template <typename Buffer, typename BufferPoolTypes, typename BaseBlock>
objcpy(Buffer * d,const C2BufferData & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)317 bool objcpy(Buffer* d, const C2BufferData& s,
318 BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
319 std::list<BaseBlock>* baseBlocks,
320 std::map<const void*, uint32_t>* baseBlockIndices) {
321 d->blocks.resize(
322 s.linearBlocks().size() +
323 s.graphicBlocks().size());
324 size_t i = 0;
325 for (const C2ConstLinearBlock& linearBlock : s.linearBlocks()) {
326 auto& dBlock = d->blocks[i++];
327 if (!objcpy(
328 &dBlock, linearBlock,
329 bufferPoolSender, baseBlocks, baseBlockIndices)) {
330 LOG(ERROR) << "Invalid C2BufferData::linearBlocks. "
331 << "(Destination index = " << i - 1 << ".)";
332 return false;
333 }
334 }
335 for (const C2ConstGraphicBlock& graphicBlock : s.graphicBlocks()) {
336 auto& dBlock = d->blocks[i++];
337 if (!objcpy(
338 &dBlock, graphicBlock,
339 bufferPoolSender, baseBlocks, baseBlockIndices)) {
340 LOG(ERROR) << "Invalid C2BufferData::graphicBlocks. "
341 << "(Destination index = " << i - 1 << ".)";
342 return false;
343 }
344 }
345 return true;
346 }
347
348 // C2Buffer -> Buffer
349 template <typename Buffer, typename BufferPoolTypes, typename BaseBlock>
objcpy(Buffer * d,const C2Buffer & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)350 bool objcpy(Buffer* d, const C2Buffer& s,
351 BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
352 std::list<BaseBlock>* baseBlocks,
353 std::map<const void*, uint32_t>* baseBlockIndices) {
354 if (!_createParamsBlob(&d->info, s.info())) {
355 LOG(ERROR) << "Invalid C2Buffer::info.";
356 return false;
357 }
358 if (!objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
359 LOG(ERROR) << "Invalid C2Buffer::data.";
360 return false;
361 }
362 return true;
363 }
364
365 // C2InfoBuffer -> InfoBuffer
366 template <typename InfoBuffer, typename BufferPoolTypes, typename BaseBlock>
objcpy(InfoBuffer * d,const C2InfoBuffer & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)367 bool objcpy(InfoBuffer* d, const C2InfoBuffer& s,
368 BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
369 std::list<BaseBlock>* baseBlocks,
370 std::map<const void*, uint32_t>* baseBlockIndices) {
371 d->index = static_cast<decltype(d->index)>(s.index());
372 auto& dBuffer = d->buffer;
373 if (!objcpy(&dBuffer, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
374 LOG(ERROR) << "Invalid C2InfoBuffer::data";
375 return false;
376 }
377 return true;
378 }
379
380 // C2FrameData -> FrameData
381 template <typename FrameData, typename BufferPoolTypes, typename BaseBlock>
objcpy(FrameData * d,const C2FrameData & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender,std::list<BaseBlock> * baseBlocks,std::map<const void *,uint32_t> * baseBlockIndices)382 bool objcpy(FrameData* d, const C2FrameData& s,
383 BufferPoolSender<BufferPoolTypes>* bufferPoolSender,
384 std::list<BaseBlock>* baseBlocks,
385 std::map<const void*, uint32_t>* baseBlockIndices) {
386 d->flags = static_cast<decltype(d->flags)>(s.flags);
387 if (!objcpy(&d->ordinal, s.ordinal)) {
388 LOG(ERROR) << "Invalid C2FrameData::ordinal.";
389 return false;
390 }
391
392 d->buffers.resize(s.buffers.size());
393 size_t i = 0;
394 for (const std::shared_ptr<C2Buffer>& sBuffer : s.buffers) {
395 auto& dBuffer = d->buffers[i++];
396 if (!sBuffer) {
397 // A null (pointer to) C2Buffer corresponds to a Buffer with empty
398 // info and blocks.
399 auto *dInfo = GetBlob(&dBuffer.info);
400 dInfo->resize(0);
401 dBuffer.blocks.resize(0);
402 continue;
403 }
404 if (!objcpy(
405 &dBuffer, *sBuffer,
406 bufferPoolSender, baseBlocks, baseBlockIndices)) {
407 LOG(ERROR) << "Invalid C2FrameData::buffers["
408 << i - 1 << "].";
409 return false;
410 }
411 }
412
413 if (!_createParamsBlob(&d->configUpdate, s.configUpdate)) {
414 LOG(ERROR) << "Invalid C2FrameData::configUpdate.";
415 return false;
416 }
417
418 d->infoBuffers.resize(s.infoBuffers.size());
419 i = 0;
420 for (const C2InfoBuffer& sInfoBuffer : s.infoBuffers) {
421 auto& dInfoBuffer = d->infoBuffers[i++];
422 if (!objcpy(&dInfoBuffer, sInfoBuffer,
423 bufferPoolSender, baseBlocks, baseBlockIndices)) {
424 LOG(ERROR) << "Invalid C2FrameData::infoBuffers["
425 << i - 1 << "].";
426 return false;
427 }
428 }
429
430 return true;
431 }
432
433 // std::list<std::unique_ptr<C2Work>> -> WorkBundle
434 template <typename WorkBundle, typename BufferPoolTypes>
objcpy(WorkBundle * d,const std::list<std::unique_ptr<C2Work>> & s,BufferPoolSender<BufferPoolTypes> * bufferPoolSender)435 bool objcpy(
436 WorkBundle* d,
437 const std::list<std::unique_ptr<C2Work>>& s,
438 BufferPoolSender<BufferPoolTypes>* bufferPoolSender) {
439 // baseBlocks holds a list of BaseBlock objects that Blocks can refer to.
440 std::list<typename decltype(d->baseBlocks)::value_type> baseBlocks;
441
442 // baseBlockIndices maps a raw pointer to native_handle_t or BufferPoolData
443 // inside baseBlocks to the corresponding index into baseBlocks. The keys
444 // (pointers) are used to identify blocks that have the same "base block" in
445 // s, a list of C2Work objects. Because baseBlocks will be copied into a
446 // hidl_vec eventually, the values of baseBlockIndices are zero-based
447 // integer indices instead of list iterators.
448 //
449 // Note that the pointers can be raw because baseBlockIndices has a shorter
450 // lifespan than all of base blocks.
451 std::map<const void*, uint32_t> baseBlockIndices;
452
453 d->works.resize(s.size());
454 size_t i = 0;
455 for (const std::unique_ptr<C2Work>& sWork : s) {
456 auto &dWork = d->works[i++];
457 if (!sWork) {
458 LOG(WARNING) << "Null C2Work encountered.";
459 continue;
460 }
461
462 // chain info is not in use currently.
463
464 // input
465 if (!objcpy(&dWork.input, sWork->input,
466 bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
467 LOG(ERROR) << "Invalid C2Work::input.";
468 return false;
469 }
470
471 // worklets
472 if (sWork->worklets.size() == 0) {
473 LOG(DEBUG) << "Work with no worklets.";
474 } else {
475 // Parcel the worklets.
476 auto &dWorklets = dWork.worklets;
477 dWorklets.resize(sWork->worklets.size());
478 size_t j = 0;
479 for (const std::unique_ptr<C2Worklet>& sWorklet : sWork->worklets)
480 {
481 if (!sWorklet) {
482 LOG(WARNING) << "Null C2Work::worklets["
483 << j << "].";
484 continue;
485 }
486 auto &dWorklet = dWorklets[j++];
487
488 // component id
489 dWorklet.componentId = static_cast<uint32_t>(
490 sWorklet->component);
491
492 // tunings
493 if (!_createParamsBlob(&dWorklet.tunings, sWorklet->tunings)) {
494 LOG(ERROR) << "Invalid C2Work::worklets["
495 << j - 1 << "]->tunings.";
496 return false;
497 }
498
499 // failures
500 dWorklet.failures.resize(sWorklet->failures.size());
501 size_t k = 0;
502 for (const std::unique_ptr<C2SettingResult>& sFailure :
503 sWorklet->failures) {
504 if (!sFailure) {
505 LOG(WARNING) << "Null C2Work::worklets["
506 << j - 1 << "]->failures["
507 << k << "].";
508 continue;
509 }
510 if (!objcpy(&dWorklet.failures[k++], *sFailure)) {
511 LOG(ERROR) << "Invalid C2Work::worklets["
512 << j - 1 << "]->failures["
513 << k - 1 << "].";
514 return false;
515 }
516 }
517
518 // output
519 if (!objcpy(&dWorklet.output, sWorklet->output,
520 bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
521 LOG(ERROR) << "Invalid C2Work::worklets["
522 << j - 1 << "]->output.";
523 return false;
524 }
525 }
526 }
527
528 // worklets processed
529 dWork.workletsProcessed = sWork->workletsProcessed;
530
531 // result
532 SetStatus(&dWork.result, sWork->result);
533 }
534
535 // Move std::list<BaseBlock> to vector<BaseBlock>.
536 {
537 d->baseBlocks.resize(baseBlocks.size());
538 size_t i = 0;
539 for (auto&& baseBlock : baseBlocks) {
540 d->baseBlocks[i++] = std::move(baseBlock);
541 }
542 }
543
544 return true;
545 }
546
547 struct C2BaseBlock {
548 enum type_t {
549 LINEAR,
550 GRAPHIC,
551 };
552 type_t type;
553 std::shared_ptr<C2LinearBlock> linear;
554 std::shared_ptr<C2GraphicBlock> graphic;
555 };
556
557 // Handle -> C2Fence
558 // Note: File descriptors are not duplicated. The original file descriptor must
559 // not be closed before the transaction is complete.
560 template <typename Handle>
objcpy(C2Fence * d,const Handle & s)561 bool objcpy(C2Fence* d, const Handle& s) {
562 const native_handle_t* handle = s.getNativeHandle();
563 *d = _C2FenceFactory::CreateFromNativeHandle(handle);
564 return true;
565 }
566
567 // C2LinearBlock, vector<C2Param*>, C2Fence -> C2Buffer
568 bool CreateLinearBuffer(
569 std::shared_ptr<C2Buffer>* buffer,
570 const std::shared_ptr<C2LinearBlock>& block,
571 const std::vector<C2Param*>& meta,
572 const C2Fence& fence);
573
574 // C2GraphicBlock, vector<C2Param*>, C2Fence -> C2Buffer
575 bool CreateGraphicBuffer(
576 std::shared_ptr<C2Buffer>* buffer,
577 const std::shared_ptr<C2GraphicBlock>& block,
578 const std::vector<C2Param*>& meta,
579 const C2Fence& fence);
580
581 // Buffer -> C2Buffer
582 // Note: The native handles will be cloned.
583 template <typename Buffer>
objcpy(std::shared_ptr<C2Buffer> * d,const Buffer & s,const std::vector<C2BaseBlock> & baseBlocks)584 bool objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
585 const std::vector<C2BaseBlock>& baseBlocks) {
586 *d = nullptr;
587
588 // Currently, a non-null C2Buffer must contain exactly 1 block.
589 if (s.blocks.size() == 0) {
590 return true;
591 } else if (s.blocks.size() != 1) {
592 LOG(ERROR) << "Invalid Buffer: "
593 "Currently, a C2Buffer must contain exactly 1 block.";
594 return false;
595 }
596
597 const auto &sBlock = s.blocks[0];
598 if (sBlock.index >= baseBlocks.size()) {
599 LOG(ERROR) << "Invalid Buffer::blocks[0].index: "
600 "Array index out of range.";
601 return false;
602 }
603 const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
604
605 // Parse meta.
606 std::vector<C2Param*> sBlockMeta;
607 if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
608 LOG(ERROR) << "Invalid Buffer::blocks[0].meta.";
609 return false;
610 }
611
612 // Copy fence.
613 C2Fence dFence;
614 if (!objcpy(&dFence, sBlock.fence)) {
615 LOG(ERROR) << "Invalid Buffer::blocks[0].fence.";
616 return false;
617 }
618
619 // Construct a block.
620 switch (baseBlock.type) {
621 case C2BaseBlock::LINEAR:
622 if (!CreateLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence)) {
623 LOG(ERROR) << "Invalid C2BaseBlock::linear.";
624 return false;
625 }
626 break;
627 case C2BaseBlock::GRAPHIC:
628 if (!CreateGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence)) {
629 LOG(ERROR) << "Invalid C2BaseBlock::graphic.";
630 return false;
631 }
632 break;
633 default:
634 LOG(ERROR) << "Invalid C2BaseBlock::type.";
635 return false;
636 }
637
638 // Parse info
639 std::vector<C2Param*> params;
640 if (!parseParamsBlob(¶ms, s.info)) {
641 LOG(ERROR) << "Invalid Buffer::info.";
642 return false;
643 }
644 for (C2Param* param : params) {
645 if (param == nullptr) {
646 LOG(ERROR) << "Null param in Buffer::info.";
647 return false;
648 }
649 std::shared_ptr<C2Param> c2param{
650 C2Param::Copy(*param).release()};
651 if (!c2param) {
652 LOG(ERROR) << "Invalid param in Buffer::info.";
653 return false;
654 }
655 c2_status_t status =
656 (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
657 if (status != C2_OK) {
658 LOG(ERROR) << "C2Buffer::setInfo failed.";
659 return false;
660 }
661 }
662
663 return true;
664 }
665
666 // InfoBuffer -> C2InfoBuffer
667 template <typename InfoBuffer>
objcpy(std::vector<C2InfoBuffer> * d,const InfoBuffer & s,const std::vector<C2BaseBlock> & baseBlocks)668 bool objcpy(
669 std::vector<C2InfoBuffer> *d,
670 const InfoBuffer& s,
671 const std::vector<C2BaseBlock>& baseBlocks) {
672
673 // Currently, a non-null C2InfoBufer must contain exactly 1 block.
674 if (s.buffer.blocks.size() == 0) {
675 return true;
676 } else if (s.buffer.blocks.size() != 1) {
677 LOG(ERROR) << "Invalid InfoBuffer::Buffer "
678 "Currently, a C2InfoBuffer must contain exactly 1 block.";
679 return false;
680 }
681
682 const auto &sBlock = s.buffer.blocks[0];
683 if (sBlock.index >= baseBlocks.size()) {
684 LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].index: "
685 "Array index out of range.";
686 return false;
687 }
688 const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
689
690 // Parse meta.
691 std::vector<C2Param*> sBlockMeta;
692 if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
693 LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].meta.";
694 return false;
695 }
696
697 // Copy fence.
698 C2Fence dFence;
699 if (!objcpy(&dFence, sBlock.fence)) {
700 LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].fence.";
701 return false;
702 }
703
704 // Construct a block.
705 switch (baseBlock.type) {
706 case C2BaseBlock::LINEAR:
707 if (sBlockMeta.size() == 1 && sBlockMeta[0] != nullptr &&
708 sBlockMeta[0]->size() == sizeof(C2Hal_RangeInfo)) {
709 C2Hal_RangeInfo *rangeInfo =
710 reinterpret_cast<C2Hal_RangeInfo*>(sBlockMeta[0]);
711 d->emplace_back(C2InfoBuffer::CreateLinearBuffer(
712 uint32_t(s.index),
713 baseBlock.linear->share(
714 rangeInfo->offset, rangeInfo->length, dFence)));
715 return true;
716 }
717 LOG(ERROR) << "Invalid Meta for C2BaseBlock::Linear InfoBuffer.";
718 break;
719 case C2BaseBlock::GRAPHIC:
720 // It's not used now
721 LOG(ERROR) << "Non-Used C2BaseBlock::type for InfoBuffer.";
722 break;
723 default:
724 LOG(ERROR) << "Invalid C2BaseBlock::type for InfoBuffer.";
725 break;
726 }
727
728 return false;
729 }
730
731 // FrameData -> C2FrameData
732 template <typename FrameData>
objcpy(C2FrameData * d,const FrameData & s,const std::vector<C2BaseBlock> & baseBlocks)733 bool objcpy(C2FrameData* d, const FrameData& s,
734 const std::vector<C2BaseBlock>& baseBlocks) {
735 d->flags = static_cast<C2FrameData::flags_t>(s.flags);
736 if (!objcpy(&d->ordinal, s.ordinal)) {
737 LOG(ERROR) << "Invalid FrameData::ordinal.";
738 return false;
739 }
740 d->buffers.clear();
741 d->buffers.reserve(s.buffers.size());
742 for (const auto& sBuffer : s.buffers) {
743 std::shared_ptr<C2Buffer> dBuffer;
744 if (!objcpy(&dBuffer, sBuffer, baseBlocks)) {
745 LOG(ERROR) << "Invalid FrameData::buffers.";
746 return false;
747 }
748 d->buffers.emplace_back(dBuffer);
749 }
750
751 std::vector<C2Param*> params;
752 if (!parseParamsBlob(¶ms, s.configUpdate)) {
753 LOG(ERROR) << "Invalid FrameData::configUpdate.";
754 return false;
755 }
756 d->configUpdate.clear();
757 for (C2Param* param : params) {
758 d->configUpdate.emplace_back(C2Param::Copy(*param));
759 if (!d->configUpdate.back()) {
760 LOG(ERROR) << "Unexpected error while parsing "
761 "FrameData::configUpdate.";
762 return false;
763 }
764 }
765
766 d->infoBuffers.clear();
767 if (s.infoBuffers.size() == 0) {
768 // InfoBuffer is optional
769 return true;
770 }
771 d->infoBuffers.reserve(s.infoBuffers.size());
772 for (const auto &sInfoBuffer: s.infoBuffers) {
773 if (!objcpy(&(d->infoBuffers), sInfoBuffer, baseBlocks)) {
774 LOG(ERROR) << "Invalid Framedata::infoBuffers.";
775 return false;
776 }
777 }
778 return true;
779 }
780
781 // BaseBlock -> C2BaseBlock
782 template <typename BaseBlock>
783 bool objcpy(C2BaseBlock* d, const BaseBlock& s);
784
785 // WorkBundle -> std::list<std::unique_ptr<C2Work>>
786 template <typename WorkBundle>
objcpy(std::list<std::unique_ptr<C2Work>> * d,const WorkBundle & s)787 bool objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
788 // Convert BaseBlocks to C2BaseBlocks.
789 std::vector<C2BaseBlock> dBaseBlocks(s.baseBlocks.size());
790 for (size_t i = 0; i < s.baseBlocks.size(); ++i) {
791 if (!objcpy(&dBaseBlocks[i], s.baseBlocks[i])) {
792 LOG(ERROR) << "Invalid WorkBundle::baseBlocks["
793 << i << "].";
794 return false;
795 }
796 }
797
798 d->clear();
799 for (const auto& sWork : s.works) {
800 d->emplace_back(std::make_unique<C2Work>());
801 C2Work& dWork = *d->back();
802
803 // chain info is not in use currently.
804
805 // input
806 if (!objcpy(&dWork.input, sWork.input, dBaseBlocks)) {
807 LOG(ERROR) << "Invalid Work::input.";
808 return false;
809 }
810
811 // worklet(s)
812 dWork.worklets.clear();
813 for (const auto& sWorklet : sWork.worklets) {
814 std::unique_ptr<C2Worklet> dWorklet = std::make_unique<C2Worklet>();
815
816 // component id
817 dWorklet->component = static_cast<c2_node_id_t>(
818 sWorklet.componentId);
819
820 // tunings
821 if (!_copyParamsFromBlob(&dWorklet->tunings, sWorklet.tunings)) {
822 LOG(ERROR) << "Invalid Worklet::tunings";
823 return false;
824 }
825
826 // failures
827 dWorklet->failures.clear();
828 dWorklet->failures.reserve(sWorklet.failures.size());
829 for (const auto& sFailure : sWorklet.failures) {
830 std::unique_ptr<C2SettingResult> dFailure;
831 if (!objcpy(&dFailure, sFailure)) {
832 LOG(ERROR) << "Invalid Worklet::failures.";
833 return false;
834 }
835 dWorklet->failures.emplace_back(std::move(dFailure));
836 }
837
838 // output
839 if (!objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks)) {
840 LOG(ERROR) << "Invalid Worklet::output.";
841 return false;
842 }
843
844 dWork.worklets.emplace_back(std::move(dWorklet));
845 }
846
847 // workletsProcessed
848 dWork.workletsProcessed = sWork.workletsProcessed;
849
850 // result
851 dWork.result = GetStatus(sWork.result);
852 }
853
854 return true;
855 }
856
857 // BufferQueue-Based Block Operations
858 // ==================================
859
860 // Call before transferring block to other processes.
861 //
862 // The given block is ready to transfer to other processes. This will guarantee
863 // the given block data is not mutated by bufferqueue migration.
864 bool BeginTransferBufferQueueBlock(const C2ConstGraphicBlock& block);
865
866 // Call beginTransferBufferQueueBlock() on blocks in the given workList.
867 // processInput determines whether input blocks are yielded. processOutput
868 // works similarly on output blocks. (The default value of processInput is
869 // false while the default value of processOutput is true. This implies that in
870 // most cases, only output buffers contain bufferqueue-based blocks.)
871 void BeginTransferBufferQueueBlocks(
872 const std::list<std::unique_ptr<C2Work>>& workList,
873 bool processInput = false,
874 bool processOutput = true);
875
876 // Call after transferring block is finished and make sure that
877 // beginTransferBufferQueueBlock() is called before.
878 //
879 // The transfer of given block is finished. If transfer is successful the given
880 // block is not owned by process anymore. Since transfer is finished the given
881 // block data is OK to mutate by bufferqueue migration after this call.
882 bool EndTransferBufferQueueBlock(const C2ConstGraphicBlock& block,
883 bool transfer);
884
885 // Call endTransferBufferQueueBlock() on blocks in the given workList.
886 // processInput determines whether input blocks are yielded. processOutput
887 // works similarly on output blocks. (The default value of processInput is
888 // false while the default value of processOutput is true. This implies that in
889 // most cases, only output buffers contain bufferqueue-based blocks.)
890 void EndTransferBufferQueueBlocks(
891 const std::list<std::unique_ptr<C2Work>>& workList,
892 bool transfer,
893 bool processInput = false,
894 bool processOutput = true);
895
896 // The given block is ready to be rendered. the given block is not owned by
897 // process anymore. If migration is in progress, this returns false in order
898 // not to render.
899 bool DisplayBufferQueueBlock(const C2ConstGraphicBlock& block);
900
901 } // namespace android
902
903 #endif // CODEC2_COMMON_BUFFER_TYPES_H
904