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 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> 37 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 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: 70 Impl(ParamRef param, C2StringLiteral name, C2StructDescriptor &&strukt) 71 : mParam(param), mName(name), _mStruct(strukt) { } 72 73 Impl(Impl&&) = default; 74 75 void addDownDependency(C2Param::Index index) { 76 mDownDependencies.push_back(index); 77 } 78 79 C2InterfaceHelper::ParamHelper::attrib_t& attrib() { 80 return mAttrib; 81 } 82 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 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 */ 126 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 134 const std::vector<ParamRef> getDependenciesAsRefs() const { 135 return mDependenciesAsRefs; 136 } 137 138 std::shared_ptr<const C2ParamDescriptor> getDescriptor() const { 139 return mDescriptor; 140 } 141 142 const std::vector<C2Param::Index> getDownDependencies() const { 143 return mDownDependencies; 144 } 145 146 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 153 C2String name() const { 154 return mName; 155 } 156 157 const ParamRef ref() const { 158 return mParam; 159 } 160 161 C2StructDescriptor retrieveStructDescriptor() { 162 return std::move(_mStruct); 163 } 164 165 void setDefaultValue(std::shared_ptr<C2Param> default_) { 166 mDefaultValue = default_; 167 } 168 169 void setDependencies(std::vector<C2Param::Index> indices, std::vector<ParamRef> refs) { 170 mDependencies = indices; 171 mDependenciesAsRefs = refs; 172 } 173 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 194 void setGetter(std::function<std::shared_ptr<C2Param>(bool)> getter) { 195 mGetter = getter; 196 } 197 198 void setSetter(std::function<C2R(const C2Param *, bool, bool *, Factory &)> setter) { 199 mSetter = setter; 200 } 201 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 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 231 std::shared_ptr<C2Param> value() { 232 return mParam.get(); 233 } 234 235 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 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 264 void C2InterfaceHelper::ParamHelper::addDownDependency(C2Param::Index index) { 265 return mImpl->addDownDependency(index); 266 } 267 268 C2InterfaceHelper::ParamHelper::attrib_t& C2InterfaceHelper::ParamHelper::attrib() { 269 return mImpl->attrib(); 270 } 271 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> 278 C2InterfaceHelper::ParamHelper::findField(size_t baseOffs, size_t baseSize) const { 279 return mImpl->findField(baseOffs, baseSize); 280 } 281 282 const std::vector<C2InterfaceHelper::ParamRef> 283 C2InterfaceHelper::ParamHelper::getDependenciesAsRefs() const { 284 return mImpl->getDependenciesAsRefs(); 285 } 286 287 std::shared_ptr<const C2ParamDescriptor> 288 C2InterfaceHelper::ParamHelper::getDescriptor() const { 289 return mImpl->getDescriptor(); 290 } 291 292 const std::vector<C2Param::Index> C2InterfaceHelper::ParamHelper::getDownDependencies() const { 293 return mImpl->getDownDependencies(); 294 } 295 296 C2Param::Index C2InterfaceHelper::ParamHelper::index() const { 297 return mImpl->index(); 298 } 299 300 C2String C2InterfaceHelper::ParamHelper::name() const { 301 return mImpl->name(); 302 } 303 304 const C2InterfaceHelper::ParamRef C2InterfaceHelper::ParamHelper::ref() const { 305 return mImpl->ref(); 306 } 307 308 C2StructDescriptor C2InterfaceHelper::ParamHelper::retrieveStructDescriptor() { 309 return mImpl->retrieveStructDescriptor(); 310 } 311 312 void C2InterfaceHelper::ParamHelper::setDefaultValue(std::shared_ptr<C2Param> default_) { 313 mImpl->setDefaultValue(default_); 314 } 315 316 void C2InterfaceHelper::ParamHelper::setDependencies( 317 std::vector<C2Param::Index> indices, std::vector<ParamRef> refs) { 318 mImpl->setDependencies(indices, refs); 319 } 320 321 void C2InterfaceHelper::ParamHelper::setFields(std::vector<C2ParamFieldValues> &&fields) { 322 return mImpl->setFields(std::move(fields)); 323 } 324 325 void C2InterfaceHelper::ParamHelper::setGetter( 326 std::function<std::shared_ptr<C2Param>(bool)> getter) { 327 mImpl->setGetter(getter); 328 } 329 330 void C2InterfaceHelper::ParamHelper::setSetter( 331 std::function<C2R(const C2Param *, bool, bool *, Factory &)> setter) { 332 mImpl->setSetter(setter); 333 } 334 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 341 c2_status_t C2InterfaceHelper::ParamHelper::validate( 342 const std::shared_ptr<C2ParamReflector> &reflector) { 343 return mImpl->validate(reflector); 344 } 345 346 std::shared_ptr<C2Param> C2InterfaceHelper::ParamHelper::value() { 347 return mImpl->value(); 348 } 349 350 std::shared_ptr<const C2Param> C2InterfaceHelper::ParamHelper::value() const { 351 return mImpl->value(); 352 } 353 354 /* ---------------------------- FieldHelper ---------------------------- */ 355 356 C2ParamField C2InterfaceHelper::FieldHelper::makeParamField(C2Param::Index index) const { 357 return _C2ParamInspector::CreateParamField(index, mFieldId); 358 } 359 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 369 void C2InterfaceHelper::FieldHelper::setSupportedValues( 370 std::unique_ptr<C2FieldSupportedValues> &&values) { 371 mSupported = std::move(values); 372 } 373 374 const C2FieldSupportedValues *C2InterfaceHelper::FieldHelper::getSupportedValues() const { 375 return (mSupported ? mSupported : mPossible).get(); 376 } 377 378 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> { 391 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 */ 399 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> 410 C2ParamFieldValuesBuilder<T> C2InterfaceHelper::Field<T>::shouldBe() const { 411 return C2ParamFieldValuesBuilder<T>(_mField); 412 } 413 414 template<typename T> 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> 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 { 444 virtual std::shared_ptr<C2ParamReflector> getReflector() const override { 445 return _mReflector; 446 } 447 448 virtual std::shared_ptr<ParamHelper> 449 getParamHelper(const ParamRef ¶m) const override { 450 return _mParams.find(param)->second; 451 } 452 453 public: 454 FactoryImpl(std::shared_ptr<C2ParamReflector> reflector) 455 : _mReflector(reflector) { } 456 457 virtual ~FactoryImpl() = default; 458 459 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 478 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 */ 490 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 495 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 506 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 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 538 C2InterfaceHelper::C2InterfaceHelper(std::shared_ptr<C2ReflectorHelper> reflector) 539 : mReflector(reflector), 540 _mFactory(std::make_shared<FactoryImpl>(reflector)) { } 541 542 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 576 void C2InterfaceHelper::addParameter(std::shared_ptr<ParamHelper> param) { 577 mReflector->addStructDescriptor(param->retrieveStructDescriptor()); 578 c2_status_t err = param->validate(mReflector); 579 if (err != C2_CORRUPTED) { 580 _mFactory->addParam(param); 581 } 582 } 583 584 c2_status_t C2InterfaceHelper::config( 585 const std::vector<C2Param*> ¶ms, c2_blocking_t mayBlock, 586 std::vector<std::unique_ptr<C2SettingResult>>* const failures, bool updateParams, 587 std::vector<std::shared_ptr<C2Param>> *changes __unused /* TODO */) { 588 bool paramWasInvalid = false; // TODO is this the same as bad value? 589 bool paramNotFound = false; 590 bool paramBadValue = false; 591 bool paramNoMemory = false; 592 bool paramBlocking = false; 593 bool paramTimedOut = false; 594 bool paramCorrupted = false; 595 596 // dependencies 597 // down dependencies are marked dirty, but params set are not immediately 598 // marked dirty (unless they become down dependency) so that we can 599 // avoid setting them if they did not change 600 601 // TODO: there could be multiple indices for the same dependency index 602 // { depIx, paramIx } may be a suitable key 603 std::map<size_t, std::pair<C2Param::Index, bool>> dependencies; 604 605 // we cannot determine the last valid parameter, so add an extra 606 // loop iteration after the last parameter 607 for (size_t p_ix = 0; p_ix <= params.size(); ++p_ix) { 608 C2Param *p = nullptr; 609 C2Param::Index paramIx = 0u; 610 size_t paramDepIx = SIZE_MAX; 611 bool last = p_ix == params.size(); 612 if (!last) { 613 p = params[p_ix]; 614 if (!*p) { 615 paramWasInvalid = true; 616 p->invalidate(); 617 continue; 618 } 619 620 paramIx = p->index(); 621 paramDepIx = getDependencyIndex(paramIx); 622 if (paramDepIx == SIZE_MAX) { 623 // unsupported parameter 624 paramNotFound = true; 625 continue; 626 } 627 628 // 629 // first insert - mark not dirty 630 // it may have been marked dirty by a dependency update 631 // this does not overrwrite(!) 632 (void)dependencies.insert({ paramDepIx, { paramIx, false /* dirty */ }}); 633 auto it = dependencies.find(paramDepIx); 634 C2_LOG(VERBOSE) << "marking dependency for setting at #" << paramDepIx << ": " 635 << it->second.first << ", update " 636 << (it->second.second ? "always (dirty)" : "only if changed"); 637 } else { 638 // process any remaining dependencies 639 if (dependencies.empty()) { 640 continue; 641 } 642 C2_LOG(VERBOSE) << "handling dirty down dependencies after last setting"; 643 } 644 645 // process any dirtied down-dependencies until the next param 646 while (dependencies.size() && dependencies.begin()->first <= paramDepIx) { 647 auto min = dependencies.begin(); 648 C2Param::Index ix = min->second.first; 649 bool dirty = min->second.second; 650 dependencies.erase(min); 651 652 std::shared_ptr<ParamHelper> param = _mFactory->getParam(ix); 653 C2_LOG(VERBOSE) << "old value " << asString(param->value().get()); 654 if (!last) { 655 C2_LOG(VERBOSE) << "new value " << asString(p); 656 } 657 if (!last && !dirty && ix == paramIx && *param->value() == *p) { 658 // no change in value - and dependencies were not updated 659 // no need to update 660 C2_LOG(VERBOSE) << "ignoring setting unchanged param " << ix; 661 continue; 662 } 663 664 // apply setting 665 bool changed = false; 666 C2_LOG(VERBOSE) << "setting param " << ix; 667 std::shared_ptr<C2Param> oldValue = param->value(); 668 c2_status_t res = param->trySet( 669 (!last && paramIx == ix) ? p : param->value().get(), mayBlock, 670 &changed, *_mFactory, failures); 671 std::shared_ptr<C2Param> newValue = param->value(); 672 C2_CHECK_EQ(oldValue == newValue, *oldValue == *newValue); 673 switch (res) { 674 case C2_OK: break; 675 case C2_BAD_VALUE: paramBadValue = true; break; 676 case C2_NO_MEMORY: paramNoMemory = true; break; 677 case C2_TIMED_OUT: paramTimedOut = true; break; 678 case C2_BLOCKING: paramBlocking = true; break; 679 case C2_CORRUPTED: paramCorrupted = true; break; 680 default: ;// TODO fatal 681 } 682 683 // copy back result for configured values (or invalidate if it does not fit or match) 684 if (updateParams && !last && paramIx == ix) { 685 if (!p->updateFrom(*param->value())) { 686 p->invalidate(); 687 } 688 } 689 690 // compare ptrs as params are copy on write 691 if (changed) { 692 C2_LOG(VERBOSE) << "param " << ix << " value changed"; 693 // value changed update down-dependencies and mark them dirty 694 for (const C2Param::Index ix : param->getDownDependencies()) { 695 C2_LOG(VERBOSE) << 1; 696 auto insert_res = dependencies.insert( 697 { getDependencyIndex(ix), { ix, true /* dirty */ }}); 698 if (!insert_res.second) { 699 (*insert_res.first).second.second = true; // mark dirty 700 } 701 702 auto it = dependencies.find(getDependencyIndex(ix)); 703 C2_CHECK(it->second.second); 704 C2_LOG(VERBOSE) << "marking down dependencies to update at #" 705 << getDependencyIndex(ix) << ": " << it->second.first; 706 } 707 } 708 } 709 } 710 711 return (paramCorrupted ? C2_CORRUPTED : 712 paramBlocking ? C2_BLOCKING : 713 paramTimedOut ? C2_TIMED_OUT : 714 paramNoMemory ? C2_NO_MEMORY : 715 (paramBadValue || paramWasInvalid) ? C2_BAD_VALUE : 716 paramNotFound ? C2_BAD_INDEX : C2_OK); 717 } 718 719 size_t C2InterfaceHelper::getDependencyIndex(C2Param::Index ix) const { 720 return _mFactory->getDependencyIndex(ix); 721 } 722 723 c2_status_t C2InterfaceHelper::query( 724 const std::vector<C2Param*> &stackParams, 725 const std::vector<C2Param::Index> &heapParamIndices, 726 c2_blocking_t mayBlock __unused /* TODO */, 727 std::vector<std::unique_ptr<C2Param>>* const heapParams) const { 728 bool paramWasInvalid = false; 729 bool paramNotFound = false; 730 bool paramDidNotFit = false; 731 bool paramNoMemory = false; 732 733 for (C2Param* const p : stackParams) { 734 if (!*p) { 735 paramWasInvalid = true; 736 p->invalidate(); 737 } else { 738 std::shared_ptr<C2Param> value = _mFactory->getParamValue(p->index()); 739 if (!value) { 740 paramNotFound = true; 741 p->invalidate(); 742 } else if (!p->updateFrom(*value)) { 743 paramDidNotFit = true; 744 p->invalidate(); 745 } 746 } 747 } 748 749 for (const C2Param::Index ix : heapParamIndices) { 750 std::shared_ptr<C2Param> value = _mFactory->getParamValue(ix); 751 if (value) { 752 std::unique_ptr<C2Param> p = C2Param::Copy(*value); 753 if (p != nullptr) { 754 heapParams->push_back(std::move(p)); 755 } else { 756 paramNoMemory = true; 757 } 758 } else { 759 paramNotFound = true; 760 } 761 } 762 763 return paramNoMemory ? C2_NO_MEMORY : 764 paramNotFound ? C2_BAD_INDEX : 765 // the following errors are not marked in the return value 766 paramDidNotFit ? C2_OK : 767 paramWasInvalid ? C2_OK : C2_OK; 768 } 769 770 c2_status_t C2InterfaceHelper::querySupportedParams( 771 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const { 772 return _mFactory->querySupportedParams(params); 773 } 774 775 776 c2_status_t C2InterfaceHelper::querySupportedValues( 777 std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock __unused) const { 778 for (C2FieldSupportedValuesQuery &query : fields) { 779 C2_LOG(VERBOSE) << "querying field " << query.field(); 780 C2Param::Index ix = _C2ParamInspector::GetIndex(query.field()); 781 std::shared_ptr<ParamHelper> param = _mFactory->getParam(ix); 782 if (!param) { 783 C2_LOG(VERBOSE) << "bad param"; 784 query.status = C2_BAD_INDEX; 785 continue; 786 } 787 size_t offs = GetBaseOffset( 788 mReflector, ix, 789 _C2ParamInspector::GetOffset(query.field()) - sizeof(C2Param)); 790 if (~offs == 0) { 791 C2_LOG(VERBOSE) << "field could not be found"; 792 query.status = C2_NOT_FOUND; 793 continue; 794 } 795 offs += sizeof(C2Param); 796 C2_LOG(VERBOSE) << "field resolved to " 797 << StringPrintf("@%02zx+%02x", offs, _C2ParamInspector::GetSize(query.field())); 798 std::shared_ptr<FieldHelper> field = 799 param->findField(offs, _C2ParamInspector::GetSize(query.field())); 800 if (!field) { 801 C2_LOG(VERBOSE) << "bad field"; 802 query.status = C2_NOT_FOUND; 803 continue; 804 } 805 806 const C2FieldSupportedValues *values = nullptr; 807 switch (query.type()) { 808 case C2FieldSupportedValuesQuery::CURRENT: 809 values = field->getSupportedValues(); 810 break; 811 case C2FieldSupportedValuesQuery::POSSIBLE: 812 values = field->getPossibleValues(); 813 break; 814 default: 815 C2_LOG(VERBOSE) << "bad query type: " << query.type(); 816 query.status = C2_BAD_VALUE; 817 } 818 if (values) { 819 query.values = *values; 820 query.status = C2_OK; 821 } else { 822 C2_LOG(DEBUG) << "no values published by component"; 823 query.status = C2_CORRUPTED; 824 } 825 } 826 return C2_OK; 827 } 828