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 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 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 759 size_t C2InterfaceHelper::getDependencyIndex_l(C2Param::Index ix) const { 760 return _mFactory->getDependencyIndex(ix); 761 } 762 763 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 813 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 820 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 874 std::unique_lock<std::mutex> C2InterfaceHelper::lock() const { 875 return std::unique_lock<std::mutex>(mMutex); 876 } 877