1 /*
2 * Copyright (C) 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 #include <C2Debug.h>
18 #include <C2ParamInternal.h>
19 #include <util/C2InterfaceHelper.h>
20
21 #include <android-base/stringprintf.h>
22
23 using ::android::base::StringPrintf;
24
25 /* --------------------------------- ReflectorHelper --------------------------------- */
26
addStructDescriptors(std::vector<C2StructDescriptor> & structs,_Tuple<> *)27 void C2ReflectorHelper::addStructDescriptors(
28 std::vector<C2StructDescriptor> &structs, _Tuple<> *) {
29 std::lock_guard<std::mutex> lock(_mMutex);
30 for (C2StructDescriptor &strukt : structs) {
31 // TODO: check if structure descriptions conflict with existing ones
32 addStructDescriptor(std::move(strukt));
33 }
34 }
35
36 std::unique_ptr<C2StructDescriptor>
describe(C2Param::CoreIndex paramIndex) const37 C2ReflectorHelper::describe(C2Param::CoreIndex paramIndex) const {
38 std::lock_guard<std::mutex> lock(_mMutex);
39 auto it = _mStructs.find(paramIndex);
40 if (it == _mStructs.end()) {
41 return nullptr;
42 } else {
43 return std::make_unique<C2StructDescriptor>(it->second);
44 }
45 };
46
addStructDescriptor(C2StructDescriptor && strukt)47 void C2ReflectorHelper::addStructDescriptor(C2StructDescriptor &&strukt) {
48 if (_mStructs.find(strukt.coreIndex()) != _mStructs.end()) {
49 // already added
50 // TODO: validate that descriptor matches stored descriptor
51 }
52 // validate that all struct fields are known to this reflector
53 for (const C2FieldDescriptor &fd : strukt) {
54 if (fd.type() & C2FieldDescriptor::STRUCT_FLAG) {
55 C2Param::CoreIndex coreIndex = fd.type() &~ C2FieldDescriptor::STRUCT_FLAG;
56 if (_mStructs.find(coreIndex) == _mStructs.end()) {
57 C2_LOG(INFO) << "missing struct descriptor #" << coreIndex << " for field "
58 << fd.name() << " of struct #" << strukt.coreIndex();
59 }
60 }
61 }
62 _mStructs.emplace(strukt.coreIndex(), strukt);
63 }
64
65
66 /* ---------------------------- ParamHelper ---------------------------- */
67
68 class C2InterfaceHelper::ParamHelper::Impl {
69 public:
Impl(ParamRef param,C2StringLiteral name,C2StructDescriptor && strukt)70 Impl(ParamRef param, C2StringLiteral name, C2StructDescriptor &&strukt)
71 : mParam(param), mName(name), _mStruct(strukt) { }
72
73 Impl(Impl&&) = default;
74
addDownDependency(C2Param::Index index)75 void addDownDependency(C2Param::Index index) {
76 mDownDependencies.push_back(index);
77 }
78
attrib()79 C2InterfaceHelper::ParamHelper::attrib_t& attrib() {
80 return mAttrib;
81 }
82
build()83 void build() {
84 // move dependencies into descriptor
85 mDescriptor = std::make_shared<C2ParamDescriptor>(
86 index(), (C2ParamDescriptor::attrib_t)mAttrib,
87 std::move(mName), std::move(mDependencies));
88 }
89
createFieldsAndSupportedValues(const std::shared_ptr<C2ParamReflector> & reflector)90 void createFieldsAndSupportedValues(const std::shared_ptr<C2ParamReflector> &reflector) {
91 for (const C2FieldUtils::Info &f :
92 C2FieldUtils::enumerateFields(*mDefaultValue, reflector)) {
93 if (!f.isArithmetic()) {
94 continue;
95 }
96 std::unique_ptr<C2FieldSupportedValues> fsvPointer;
97
98 // create a breakable structure
99 do {
100 C2FieldSupportedValues fsv;
101 switch (f.type()) {
102 case C2FieldDescriptor::INT32: fsv = C2SupportedRange<int32_t>::Any(); break;
103 case C2FieldDescriptor::UINT32: fsv = C2SupportedRange<uint32_t>::Any(); break;
104 case C2FieldDescriptor::INT64: fsv = C2SupportedRange<int64_t>::Any(); break;
105 case C2FieldDescriptor::UINT64: fsv = C2SupportedRange<uint64_t>::Any(); break;
106 case C2FieldDescriptor::FLOAT: fsv = C2SupportedRange<float>::Any(); break;
107 case C2FieldDescriptor::BLOB: fsv = C2SupportedRange<uint8_t>::Any(); break;
108 case C2FieldDescriptor::STRING: fsv = C2SupportedRange<char>::Any(); break;
109 default:
110 continue; // break out of do {} while
111 }
112 fsvPointer = std::make_unique<C2FieldSupportedValues>(fsv);
113 } while (false);
114
115 mFields.emplace_hint(
116 mFields.end(),
117 _C2FieldId(f.offset(), f.size()),
118 std::make_shared<FieldHelper>(
119 mParam, _C2FieldId(f.offset(), f.size()), std::move(fsvPointer)));
120 }
121 }
122
123 /**
124 * Finds a field descriptor.
125 */
findField(size_t baseOffs,size_t baseSize) const126 std::shared_ptr<FieldHelper> findField(size_t baseOffs, size_t baseSize) const {
127 auto it = mFields.find(_C2FieldId(baseOffs, baseSize));
128 if (it == mFields.end()) {
129 return nullptr;
130 }
131 return it->second;
132 }
133
getDependenciesAsRefs() const134 const std::vector<ParamRef> getDependenciesAsRefs() const {
135 return mDependenciesAsRefs;
136 }
137
getDescriptor() const138 std::shared_ptr<const C2ParamDescriptor> getDescriptor() const {
139 return mDescriptor;
140 }
141
getDownDependencies() const142 const std::vector<C2Param::Index> getDownDependencies() const {
143 return mDownDependencies;
144 }
145
index() const146 C2Param::Index index() const {
147 if (!mDefaultValue) {
148 fprintf(stderr, "%s missing default value\n", mName.c_str());
149 }
150 return mDefaultValue->index();
151 }
152
name() const153 C2String name() const {
154 return mName;
155 }
156
ref() const157 const ParamRef ref() const {
158 return mParam;
159 }
160
retrieveStructDescriptor()161 C2StructDescriptor retrieveStructDescriptor() {
162 return std::move(_mStruct);
163 }
164
setDefaultValue(std::shared_ptr<C2Param> default_)165 void setDefaultValue(std::shared_ptr<C2Param> default_) {
166 mDefaultValue = default_;
167 }
168
setDependencies(std::vector<C2Param::Index> indices,std::vector<ParamRef> refs)169 void setDependencies(std::vector<C2Param::Index> indices, std::vector<ParamRef> refs) {
170 mDependencies = indices;
171 mDependenciesAsRefs = refs;
172 }
173
setFields(std::vector<C2ParamFieldValues> && fields)174 void setFields(std::vector<C2ParamFieldValues> &&fields) {
175 // do not allow adding fields multiple times, or to const values
176 if (!mFields.empty()) {
177 C2_LOG(FATAL) << "Trying to add fields to param " << mName << " multiple times";
178 } else if (mAttrib & attrib_t::IS_CONST) {
179 C2_LOG(FATAL) << "Trying to add fields to const param " << mName;
180 }
181
182 for (C2ParamFieldValues &pfv : fields) {
183 mFields.emplace_hint(
184 mFields.end(),
185 // _C2FieldId constructor
186 _C2ParamInspector::GetField(pfv.paramOrField),
187 // Field constructor
188 std::make_shared<FieldHelper>(mParam,
189 _C2ParamInspector::GetField(pfv.paramOrField),
190 std::move(pfv.values)));
191 }
192 }
193
setGetter(std::function<std::shared_ptr<C2Param> (bool)> getter)194 void setGetter(std::function<std::shared_ptr<C2Param>(bool)> getter) {
195 mGetter = getter;
196 }
197
setSetter(std::function<C2R (const C2Param *,bool,bool *,Factory &)> setter)198 void setSetter(std::function<C2R(const C2Param *, bool, bool *, Factory &)> setter) {
199 mSetter = setter;
200 }
201
trySet(const C2Param * value,bool mayBlock,bool * changed,Factory & f,std::vector<std::unique_ptr<C2SettingResult>> * const failures)202 c2_status_t trySet(
203 const C2Param *value, bool mayBlock, bool *changed, Factory &f,
204 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
205 C2R result = mSetter(value, mayBlock, changed, f);
206 return result.retrieveFailures(failures);
207 }
208
validate(const std::shared_ptr<C2ParamReflector> & reflector)209 c2_status_t validate(const std::shared_ptr<C2ParamReflector> &reflector) {
210 if (!mSetter && mFields.empty()) {
211 C2_LOG(WARNING) << "Param " << mName << " has no setter, making it const";
212 // dependencies are empty in this case
213 mAttrib |= attrib_t::IS_CONST;
214 } else if (!mSetter) {
215 C2_LOG(FATAL) << "Param " << mName << " has no setter";
216 }
217
218 if (mAttrib & attrib_t::IS_CONST) {
219 createFieldsAndSupportedValues(reflector);
220 } else {
221 // TODO: update default based on setter and verify that FSV covers the values
222 }
223
224 if (mFields.empty()) {
225 C2_LOG(FATAL) << "Param " << mName << " has no fields";
226 }
227
228 return C2_OK;
229 }
230
value()231 std::shared_ptr<C2Param> value() {
232 return mParam.get();
233 }
234
value() const235 std::shared_ptr<const C2Param> value() const {
236 return mParam.get();
237 }
238
239 private:
240 typedef _C2ParamInspector::attrib_t attrib_t;
241 ParamRef mParam;
242 C2String mName;
243 C2StructDescriptor _mStruct;
244 std::shared_ptr<C2Param> mDefaultValue;
245 attrib_t mAttrib;
246 std::function<C2R(const C2Param *, bool, bool *, Factory &)> mSetter;
247 std::function<std::shared_ptr<C2Param>(bool)> mGetter;
248 std::vector<C2Param::Index> mDependencies;
249 std::vector<ParamRef> mDependenciesAsRefs;
250 std::vector<C2Param::Index> mDownDependencies; // TODO: this does not work for stream dependencies
251 std::map<_C2FieldId, std::shared_ptr<FieldHelper>> mFields;
252 std::shared_ptr<C2ParamDescriptor> mDescriptor;
253 };
254
ParamHelper(ParamRef param,C2StringLiteral name,C2StructDescriptor && strukt)255 C2InterfaceHelper::ParamHelper::ParamHelper(
256 ParamRef param, C2StringLiteral name, C2StructDescriptor &&strukt)
257 : mImpl(std::make_unique<C2InterfaceHelper::ParamHelper::Impl>(
258 param, name, std::move(strukt))) { }
259
260 C2InterfaceHelper::ParamHelper::ParamHelper(C2InterfaceHelper::ParamHelper &&) = default;
261
262 C2InterfaceHelper::ParamHelper::~ParamHelper() = default;
263
addDownDependency(C2Param::Index index)264 void C2InterfaceHelper::ParamHelper::addDownDependency(C2Param::Index index) {
265 return mImpl->addDownDependency(index);
266 }
267
attrib()268 C2InterfaceHelper::ParamHelper::attrib_t& C2InterfaceHelper::ParamHelper::attrib() {
269 return mImpl->attrib();
270 }
271
build()272 std::shared_ptr<C2InterfaceHelper::ParamHelper> C2InterfaceHelper::ParamHelper::build() {
273 mImpl->build();
274 return std::make_shared<C2InterfaceHelper::ParamHelper>(std::move(*this));
275 }
276
277 std::shared_ptr<C2InterfaceHelper::FieldHelper>
findField(size_t baseOffs,size_t baseSize) const278 C2InterfaceHelper::ParamHelper::findField(size_t baseOffs, size_t baseSize) const {
279 return mImpl->findField(baseOffs, baseSize);
280 }
281
282 const std::vector<C2InterfaceHelper::ParamRef>
getDependenciesAsRefs() const283 C2InterfaceHelper::ParamHelper::getDependenciesAsRefs() const {
284 return mImpl->getDependenciesAsRefs();
285 }
286
287 std::shared_ptr<const C2ParamDescriptor>
getDescriptor() const288 C2InterfaceHelper::ParamHelper::getDescriptor() const {
289 return mImpl->getDescriptor();
290 }
291
getDownDependencies() const292 const std::vector<C2Param::Index> C2InterfaceHelper::ParamHelper::getDownDependencies() const {
293 return mImpl->getDownDependencies();
294 }
295
index() const296 C2Param::Index C2InterfaceHelper::ParamHelper::index() const {
297 return mImpl->index();
298 }
299
name() const300 C2String C2InterfaceHelper::ParamHelper::name() const {
301 return mImpl->name();
302 }
303
ref() const304 const C2InterfaceHelper::ParamRef C2InterfaceHelper::ParamHelper::ref() const {
305 return mImpl->ref();
306 }
307
retrieveStructDescriptor()308 C2StructDescriptor C2InterfaceHelper::ParamHelper::retrieveStructDescriptor() {
309 return mImpl->retrieveStructDescriptor();
310 }
311
setDefaultValue(std::shared_ptr<C2Param> default_)312 void C2InterfaceHelper::ParamHelper::setDefaultValue(std::shared_ptr<C2Param> default_) {
313 mImpl->setDefaultValue(default_);
314 }
315
setDependencies(std::vector<C2Param::Index> indices,std::vector<ParamRef> refs)316 void C2InterfaceHelper::ParamHelper::setDependencies(
317 std::vector<C2Param::Index> indices, std::vector<ParamRef> refs) {
318 mImpl->setDependencies(indices, refs);
319 }
320
setFields(std::vector<C2ParamFieldValues> && fields)321 void C2InterfaceHelper::ParamHelper::setFields(std::vector<C2ParamFieldValues> &&fields) {
322 return mImpl->setFields(std::move(fields));
323 }
324
setGetter(std::function<std::shared_ptr<C2Param> (bool)> getter)325 void C2InterfaceHelper::ParamHelper::setGetter(
326 std::function<std::shared_ptr<C2Param>(bool)> getter) {
327 mImpl->setGetter(getter);
328 }
329
setSetter(std::function<C2R (const C2Param *,bool,bool *,Factory &)> setter)330 void C2InterfaceHelper::ParamHelper::setSetter(
331 std::function<C2R(const C2Param *, bool, bool *, Factory &)> setter) {
332 mImpl->setSetter(setter);
333 }
334
trySet(const C2Param * value,bool mayBlock,bool * changed,Factory & f,std::vector<std::unique_ptr<C2SettingResult>> * const failures)335 c2_status_t C2InterfaceHelper::ParamHelper::trySet(
336 const C2Param *value, bool mayBlock, bool *changed, Factory &f,
337 std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
338 return mImpl->trySet(value, mayBlock, changed, f, failures);
339 }
340
validate(const std::shared_ptr<C2ParamReflector> & reflector)341 c2_status_t C2InterfaceHelper::ParamHelper::validate(
342 const std::shared_ptr<C2ParamReflector> &reflector) {
343 return mImpl->validate(reflector);
344 }
345
value()346 std::shared_ptr<C2Param> C2InterfaceHelper::ParamHelper::value() {
347 return mImpl->value();
348 }
349
value() const350 std::shared_ptr<const C2Param> C2InterfaceHelper::ParamHelper::value() const {
351 return mImpl->value();
352 }
353
354 /* ---------------------------- FieldHelper ---------------------------- */
355
makeParamField(C2Param::Index index) const356 C2ParamField C2InterfaceHelper::FieldHelper::makeParamField(C2Param::Index index) const {
357 return _C2ParamInspector::CreateParamField(index, mFieldId);
358 }
359
FieldHelper(const ParamRef & param,const _C2FieldId & field,std::unique_ptr<C2FieldSupportedValues> && values)360 C2InterfaceHelper::FieldHelper::FieldHelper(const ParamRef ¶m, const _C2FieldId &field,
361 std::unique_ptr<C2FieldSupportedValues> &&values)
362 : mParam(param),
363 mFieldId(field),
364 mPossible(std::move(values)) {
365 C2_LOG(VERBOSE) << "Creating field helper " << field << " "
366 << C2FieldSupportedValuesHelper<uint32_t>(*mPossible);
367 }
368
setSupportedValues(std::unique_ptr<C2FieldSupportedValues> && values)369 void C2InterfaceHelper::FieldHelper::setSupportedValues(
370 std::unique_ptr<C2FieldSupportedValues> &&values) {
371 mSupported = std::move(values);
372 }
373
getSupportedValues() const374 const C2FieldSupportedValues *C2InterfaceHelper::FieldHelper::getSupportedValues() const {
375 return (mSupported ? mSupported : mPossible).get();
376 }
377
getPossibleValues() const378 const C2FieldSupportedValues *C2InterfaceHelper::FieldHelper::getPossibleValues() const {
379 return mPossible.get();
380 }
381
382
383 /* ---------------------------- Field ---------------------------- */
384
385 /**
386 * Wrapper around field-supported-values builder that gets stored in the
387 * field helper when the builder goes out of scope.
388 */
389 template<typename T>
390 struct SupportedValuesBuilder : C2ParamFieldValuesBuilder<T> {
SupportedValuesBuilderSupportedValuesBuilder391 SupportedValuesBuilder(
392 C2ParamField &field, std::shared_ptr<C2InterfaceHelper::FieldHelper> helper)
393 : C2ParamFieldValuesBuilder<T>(field), _mHelper(helper), _mField(field) {
394 }
395
396 /**
397 * Save builder values on destruction.
398 */
~SupportedValuesBuilderSupportedValuesBuilder399 virtual ~SupportedValuesBuilder() override {
400 _mHelper->setSupportedValues(std::move(C2ParamFieldValues(*this).values));
401 }
402
403 private:
404 std::shared_ptr<C2InterfaceHelper::FieldHelper> _mHelper;
405 C2ParamField _mField;
406 };
407
408
409 template<typename T>
shouldBe() const410 C2ParamFieldValuesBuilder<T> C2InterfaceHelper::Field<T>::shouldBe() const {
411 return C2ParamFieldValuesBuilder<T>(_mField);
412 }
413
414 template<typename T>
mustBe()415 C2ParamFieldValuesBuilder<T> C2InterfaceHelper::Field<T>::mustBe() {
416 return SupportedValuesBuilder<T>(_mField, _mHelper);
417 }
418
419 /*
420 template<typename T> C2SettingResultsBuilder C2InterfaceHelper::Field<T>::validatePossible(T &value)
421 const {
422 /// TODO
423 return C2SettingResultsBuilder::Ok();
424 }
425 */
426
427 template<typename T>
Field(std::shared_ptr<FieldHelper> helper,C2Param::Index index)428 C2InterfaceHelper::Field<T>::Field(std::shared_ptr<FieldHelper> helper, C2Param::Index index)
429 : _mHelper(helper), _mField(helper->makeParamField(index)) { }
430
431 template struct C2InterfaceHelper::Field<uint8_t>;
432 template struct C2InterfaceHelper::Field<char>;
433 template struct C2InterfaceHelper::Field<int32_t>;
434 template struct C2InterfaceHelper::Field<uint32_t>;
435 //template struct C2InterfaceHelper::Field<c2_cntr32_t>;
436 template struct C2InterfaceHelper::Field<int64_t>;
437 template struct C2InterfaceHelper::Field<uint64_t>;
438 //template struct C2InterfaceHelper::Field<c2_cntr64_t>;
439 template struct C2InterfaceHelper::Field<float>;
440
441 /* --------------------------------- Factory --------------------------------- */
442
443 struct C2InterfaceHelper::FactoryImpl : public C2InterfaceHelper::Factory {
getReflectorC2InterfaceHelper::FactoryImpl444 virtual std::shared_ptr<C2ParamReflector> getReflector() const override {
445 return _mReflector;
446 }
447
448 virtual std::shared_ptr<ParamHelper>
getParamHelperC2InterfaceHelper::FactoryImpl449 getParamHelper(const ParamRef ¶m) const override {
450 return _mParams.find(param)->second;
451 }
452
453 public:
FactoryImplC2InterfaceHelper::FactoryImpl454 FactoryImpl(std::shared_ptr<C2ParamReflector> reflector)
455 : _mReflector(reflector) { }
456
457 virtual ~FactoryImpl() = default;
458
addParamC2InterfaceHelper::FactoryImpl459 void addParam(std::shared_ptr<ParamHelper> param) {
460 _mParams.insert({ param->ref(), param });
461 _mIndexToHelper.insert({param->index(), param});
462
463 // add down-dependencies (and validate dependencies as a result)
464 size_t ix = 0;
465 for (const ParamRef &ref : param->getDependenciesAsRefs()) {
466 // dependencies must already be defined
467 if (!_mParams.count(ref)) {
468 C2_LOG(FATAL) << "Parameter " << param->name() << " has a dependency at index "
469 << ix << " that is not yet defined";
470 }
471 _mParams.find(ref)->second->addDownDependency(param->index());
472 ++ix;
473 }
474
475 _mDependencyIndex.emplace(param->index(), _mDependencyIndex.size());
476 }
477
getParamC2InterfaceHelper::FactoryImpl478 std::shared_ptr<ParamHelper> getParam(C2Param::Index ix) const {
479 // TODO: handle streams separately
480 const auto it = _mIndexToHelper.find(ix);
481 if (it == _mIndexToHelper.end()) {
482 return nullptr;
483 }
484 return it->second;
485 }
486
487 /**
488 * TODO: this could return a copy using proper pointer cast.
489 */
getParamValueC2InterfaceHelper::FactoryImpl490 std::shared_ptr<C2Param> getParamValue(C2Param::Index ix) const {
491 std::shared_ptr<ParamHelper> helper = getParam(ix);
492 return helper ? helper->value() : nullptr;
493 }
494
querySupportedParamsC2InterfaceHelper::FactoryImpl495 c2_status_t querySupportedParams(
496 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
497 for (const auto &it : _mParams) {
498 // TODO: change querySupportedParams signature?
499 params->push_back(
500 std::const_pointer_cast<C2ParamDescriptor>(it.second->getDescriptor()));
501 }
502 // TODO: handle errors
503 return C2_OK;
504 }
505
getDependencyIndexC2InterfaceHelper::FactoryImpl506 size_t getDependencyIndex(C2Param::Index ix) {
507 // in this version of the helper there is only a single stream so
508 // we can look up directly by index
509 auto it = _mDependencyIndex.find(ix);
510 return it == _mDependencyIndex.end() ? SIZE_MAX : it->second;
511 }
512
513 private:
514 std::map<ParamRef, std::shared_ptr<ParamHelper>> _mParams;
515 std::map<C2Param::Index, std::shared_ptr<ParamHelper>> _mIndexToHelper;
516 std::shared_ptr<C2ParamReflector> _mReflector;
517 std::map<C2Param::Index, size_t> _mDependencyIndex;
518 };
519
520 /* --------------------------------- Helper --------------------------------- */
521
522 namespace {
523
asString(C2Param * p)524 static std::string asString(C2Param *p) {
525 char addr[20];
526 sprintf(addr, "%p:[", p);
527 std::string v = addr;
528 for (size_t i = 0; i < p->size(); ++i) {
529 char d[4];
530 sprintf(d, " %02x", *(((uint8_t *)p) + i));
531 v += d + (i == 0);
532 }
533 return v + "]";
534 }
535
536 }
537
C2InterfaceHelper(std::shared_ptr<C2ReflectorHelper> reflector)538 C2InterfaceHelper::C2InterfaceHelper(std::shared_ptr<C2ReflectorHelper> reflector)
539 : mReflector(reflector),
540 _mFactory(std::make_shared<FactoryImpl>(reflector)) { }
541
542
GetBaseOffset(const std::shared_ptr<C2ParamReflector> & reflector,C2Param::CoreIndex index,size_t offset)543 size_t C2InterfaceHelper::GetBaseOffset(const std::shared_ptr<C2ParamReflector> &reflector,
544 C2Param::CoreIndex index, size_t offset) {
545 std::unique_ptr<C2StructDescriptor> param = reflector->describe(index);
546 if (param == nullptr) {
547 return ~(size_t)0; // param structure not described
548 }
549
550 for (const C2FieldDescriptor &field : *param) {
551 size_t fieldOffset = _C2ParamInspector::GetOffset(field);
552 size_t fieldSize = _C2ParamInspector::GetSize(field);
553 size_t fieldExtent = field.extent();
554 if (offset < fieldOffset) {
555 return ~(size_t)0; // not found
556 }
557 if (offset == fieldOffset) {
558 // exact match
559 return offset;
560 }
561 if (field.extent() == 0 || offset < fieldOffset + fieldSize * fieldExtent) {
562 // reduce to first element in case of array
563 offset = fieldOffset + (offset - fieldOffset) % fieldSize;
564 if (field.type() >= C2FieldDescriptor::STRUCT_FLAG) {
565 // this offset is within a field
566 offset = GetBaseOffset(
567 reflector, field.type() & ~C2FieldDescriptor::STRUCT_FLAG,
568 offset - fieldOffset);
569 return ~offset ? fieldOffset + offset : offset;
570 }
571 }
572 }
573 return ~(size_t)0; // not found
574 }
575
addParameter(std::shared_ptr<ParamHelper> param)576 void C2InterfaceHelper::addParameter(std::shared_ptr<ParamHelper> param) {
577 std::lock_guard<std::mutex> lock(mMutex);
578 mReflector->addStructDescriptor(param->retrieveStructDescriptor());
579 c2_status_t err = param->validate(mReflector);
580 if (err != C2_CORRUPTED) {
581 _mFactory->addParam(param);
582
583 // run setter to ensure correct values
584 bool changed = false;
585 std::vector<std::unique_ptr<C2SettingResult>> failures;
586 (void)param->trySet(param->value().get(), C2_MAY_BLOCK, &changed, *_mFactory, &failures);
587 }
588 }
589
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures,bool updateParams,std::vector<std::shared_ptr<C2Param>> * changes __unused)590 c2_status_t C2InterfaceHelper::config(
591 const std::vector<C2Param*> ¶ms, c2_blocking_t mayBlock,
592 std::vector<std::unique_ptr<C2SettingResult>>* const failures, bool updateParams,
593 std::vector<std::shared_ptr<C2Param>> *changes __unused /* TODO */) {
594 std::lock_guard<std::mutex> lock(mMutex);
595 bool paramWasInvalid = false; // TODO is this the same as bad value?
596 bool paramNotFound = false;
597 bool paramBadValue = false;
598 bool paramNoMemory = false;
599 bool paramBlocking = false;
600 bool paramTimedOut = false;
601 bool paramCorrupted = false;
602
603 // dependencies
604 // down dependencies are marked dirty, but params set are not immediately
605 // marked dirty (unless they become down dependency) so that we can
606 // avoid setting them if they did not change
607
608 // TODO: there could be multiple indices for the same dependency index
609 // { depIx, paramIx } may be a suitable key
610 std::map<size_t, std::pair<C2Param::Index, bool>> dependencies;
611
612 std::vector<std::unique_ptr<C2Param>> paramRequests;
613 std::vector<C2Param*> lateReadParams;
614
615 // we cannot determine the last valid parameter, so add an extra
616 // loop iteration after the last parameter
617 for (size_t p_ix = 0; p_ix <= params.size(); ++p_ix) {
618 C2Param *p = nullptr;
619 C2Param::Index paramIx = 0u;
620 size_t paramDepIx = SIZE_MAX;
621 bool last = p_ix == params.size();
622 if (!last) {
623 p = params[p_ix];
624 if (!*p) {
625 paramWasInvalid = true;
626 p->invalidate();
627 continue;
628 }
629
630 paramIx = p->index();
631
632 // convert parameter to request in case this is a split parameter
633 C2Param::Index requestParamIx = paramIx | C2Param::CoreIndex::IS_REQUEST_FLAG;
634
635 // setting a request directly is handled as normal
636 if (paramIx != requestParamIx) {
637 paramDepIx = getDependencyIndex_l(requestParamIx);
638 if (paramDepIx == SIZE_MAX) {
639 // not a split parameter, handle it normally
640 paramDepIx = getDependencyIndex_l(paramIx);
641 } else {
642 // split parameter - replace with setting for the request - and queue to
643 // read back actual value
644 // TODO: read late params at the right time
645 lateReadParams.emplace_back(p);
646 std::unique_ptr<C2Param> request(C2Param::CopyAsRequest(*p));
647 p = request.get();
648 paramRequests.emplace_back(std::move(request));
649 }
650 }
651
652 if (paramDepIx == SIZE_MAX) {
653 // unsupported parameter
654 paramNotFound = true;
655 continue;
656 }
657
658 //
659 // first insert - mark not dirty
660 // it may have been marked dirty by a dependency update
661 // this does not overrwrite(!)
662 (void)dependencies.insert({ paramDepIx, { paramIx, false /* dirty */ }});
663 auto it = dependencies.find(paramDepIx);
664 C2_LOG(VERBOSE) << "marking dependency for setting at #" << paramDepIx << ": "
665 << it->second.first << ", update "
666 << (it->second.second ? "always (dirty)" : "only if changed");
667 } else {
668 // process any remaining dependencies
669 if (dependencies.empty()) {
670 continue;
671 }
672 C2_LOG(VERBOSE) << "handling dirty down dependencies after last setting";
673 }
674
675 // process any dirtied down-dependencies until the next param
676 while (dependencies.size() && dependencies.begin()->first <= paramDepIx) {
677 auto min = dependencies.begin();
678 C2Param::Index ix = min->second.first;
679 bool dirty = min->second.second;
680 dependencies.erase(min);
681
682 std::shared_ptr<ParamHelper> param = _mFactory->getParam(ix);
683 C2_LOG(VERBOSE) << "old value " << asString(param->value().get());
684 if (!last) {
685 C2_LOG(VERBOSE) << "new value " << asString(p);
686 }
687 if (!last && !dirty && ix == paramIx && *param->value() == *p) {
688 // no change in value - and dependencies were not updated
689 // no need to update
690 C2_LOG(VERBOSE) << "ignoring setting unchanged param " << ix;
691 continue;
692 }
693
694 // apply setting
695 bool changed = false;
696 C2_LOG(VERBOSE) << "setting param " << ix;
697 std::shared_ptr<C2Param> oldValue = param->value();
698 c2_status_t res = param->trySet(
699 (!last && paramIx == ix) ? p : param->value().get(), mayBlock,
700 &changed, *_mFactory, failures);
701 std::shared_ptr<C2Param> newValue = param->value();
702 C2_CHECK_EQ(oldValue == newValue, *oldValue == *newValue);
703 switch (res) {
704 case C2_OK: break;
705 case C2_BAD_VALUE: paramBadValue = true; break;
706 case C2_NO_MEMORY: paramNoMemory = true; break;
707 case C2_TIMED_OUT: paramTimedOut = true; break;
708 case C2_BLOCKING: paramBlocking = true; break;
709 case C2_CORRUPTED: paramCorrupted = true; break;
710 default: ;// TODO fatal
711 }
712
713 // copy back result for configured values (or invalidate if it does not fit or match)
714 if (updateParams && !last && paramIx == ix) {
715 if (!p->updateFrom(*param->value())) {
716 p->invalidate();
717 }
718 }
719
720 // compare ptrs as params are copy on write
721 if (changed) {
722 C2_LOG(VERBOSE) << "param " << ix << " value changed";
723 // value changed update down-dependencies and mark them dirty
724 for (const C2Param::Index ix : param->getDownDependencies()) {
725 C2_LOG(VERBOSE) << 1;
726 auto insert_res = dependencies.insert(
727 { getDependencyIndex_l(ix), { ix, true /* dirty */ }});
728 if (!insert_res.second) {
729 (*insert_res.first).second.second = true; // mark dirty
730 }
731
732 auto it = dependencies.find(getDependencyIndex_l(ix));
733 C2_CHECK(it->second.second);
734 C2_LOG(VERBOSE) << "marking down dependencies to update at #"
735 << getDependencyIndex_l(ix) << ": " << it->second.first;
736 }
737 }
738 }
739 }
740
741 // get late read parameters
742 for (C2Param *p : lateReadParams) {
743 std::shared_ptr<C2Param> value = _mFactory->getParamValue(p->index());
744 if (value) {
745 p->updateFrom(*value);
746 } else {
747 p->invalidate();
748 }
749 }
750
751 return (paramCorrupted ? C2_CORRUPTED :
752 paramBlocking ? C2_BLOCKING :
753 paramTimedOut ? C2_TIMED_OUT :
754 paramNoMemory ? C2_NO_MEMORY :
755 (paramBadValue || paramWasInvalid) ? C2_BAD_VALUE :
756 paramNotFound ? C2_BAD_INDEX : C2_OK);
757 }
758
getDependencyIndex_l(C2Param::Index ix) const759 size_t C2InterfaceHelper::getDependencyIndex_l(C2Param::Index ix) const {
760 return _mFactory->getDependencyIndex(ix);
761 }
762
query(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock __unused,std::vector<std::unique_ptr<C2Param>> * const heapParams) const763 c2_status_t C2InterfaceHelper::query(
764 const std::vector<C2Param*> &stackParams,
765 const std::vector<C2Param::Index> &heapParamIndices,
766 c2_blocking_t mayBlock __unused /* TODO */,
767 std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
768 std::lock_guard<std::mutex> lock(mMutex);
769 bool paramWasInvalid = false;
770 bool paramNotFound = false;
771 bool paramDidNotFit = false;
772 bool paramNoMemory = false;
773
774 for (C2Param* const p : stackParams) {
775 if (!*p) {
776 paramWasInvalid = true;
777 p->invalidate();
778 } else {
779 std::shared_ptr<C2Param> value = _mFactory->getParamValue(p->index());
780 if (!value) {
781 paramNotFound = true;
782 p->invalidate();
783 } else if (!p->updateFrom(*value)) {
784 paramDidNotFit = true;
785 p->invalidate();
786 }
787 }
788 }
789
790 for (const C2Param::Index ix : heapParamIndices) {
791 std::shared_ptr<C2Param> value = _mFactory->getParamValue(ix);
792 if (value) {
793 std::unique_ptr<C2Param> p = C2Param::Copy(*value);
794 if (p != nullptr) {
795 heapParams->push_back(std::move(p));
796 } else {
797 heapParams->push_back(nullptr);
798 paramNoMemory = true;
799 }
800 } else {
801 heapParams->push_back(nullptr);
802 paramNotFound = true;
803 }
804 }
805
806 return paramNoMemory ? C2_NO_MEMORY :
807 paramNotFound ? C2_BAD_INDEX :
808 // the following errors are not marked in the return value
809 paramDidNotFit ? C2_OK :
810 paramWasInvalid ? C2_OK : C2_OK;
811 }
812
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const813 c2_status_t C2InterfaceHelper::querySupportedParams(
814 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
815 std::lock_guard<std::mutex> lock(mMutex);
816 return _mFactory->querySupportedParams(params);
817 }
818
819
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock __unused) const820 c2_status_t C2InterfaceHelper::querySupportedValues(
821 std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock __unused) const {
822 std::lock_guard<std::mutex> lock(mMutex);
823 for (C2FieldSupportedValuesQuery &query : fields) {
824 C2_LOG(VERBOSE) << "querying field " << query.field();
825 C2Param::Index ix = _C2ParamInspector::GetIndex(query.field());
826 std::shared_ptr<ParamHelper> param = _mFactory->getParam(ix);
827 if (!param) {
828 C2_LOG(VERBOSE) << "bad param";
829 query.status = C2_BAD_INDEX;
830 continue;
831 }
832 size_t offs = GetBaseOffset(
833 mReflector, ix,
834 _C2ParamInspector::GetOffset(query.field()) - sizeof(C2Param));
835 if (~offs == 0) {
836 C2_LOG(VERBOSE) << "field could not be found";
837 query.status = C2_NOT_FOUND;
838 continue;
839 }
840 offs += sizeof(C2Param);
841 C2_LOG(VERBOSE) << "field resolved to "
842 << StringPrintf("@%02zx+%02x", offs, _C2ParamInspector::GetSize(query.field()));
843 std::shared_ptr<FieldHelper> field =
844 param->findField(offs, _C2ParamInspector::GetSize(query.field()));
845 if (!field) {
846 C2_LOG(VERBOSE) << "bad field";
847 query.status = C2_NOT_FOUND;
848 continue;
849 }
850
851 const C2FieldSupportedValues *values = nullptr;
852 switch (query.type()) {
853 case C2FieldSupportedValuesQuery::CURRENT:
854 values = field->getSupportedValues();
855 break;
856 case C2FieldSupportedValuesQuery::POSSIBLE:
857 values = field->getPossibleValues();
858 break;
859 default:
860 C2_LOG(VERBOSE) << "bad query type: " << query.type();
861 query.status = C2_BAD_VALUE;
862 }
863 if (values) {
864 query.values = *values;
865 query.status = C2_OK;
866 } else {
867 C2_LOG(DEBUG) << "no values published by component";
868 query.status = C2_CORRUPTED;
869 }
870 }
871 return C2_OK;
872 }
873
lock() const874 std::unique_lock<std::mutex> C2InterfaceHelper::lock() const {
875 return std::unique_lock<std::mutex>(mMutex);
876 }
877