1 /*
2  * Copyright 2014 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "C2SampleComponent_test"
19 
20 #include <gtest/gtest.h>
21 
22 #define __C2_GENERATE_GLOBAL_VARS__
23 #include <C2Component.h>
24 #include <C2Config.h>
25 #include <C2Debug.h>
26 #include <C2Enum.h>
27 
28 #include <unordered_map>
29 
30 class C2SampleComponentTest : public ::testing::Test {
31 };
32 
PrintTo(const C2FieldDescriptor & fd,::std::ostream * os)33 void PrintTo(const C2FieldDescriptor &fd, ::std::ostream *os) {
34     using FD=C2FieldDescriptor;
35     switch (fd.type()) {
36     case FD::INT32: *os << "i32"; break;
37     case FD::INT64: *os << "i64"; break;
38     case FD::UINT32: *os << "u32"; break;
39     case FD::UINT64: *os << "u64"; break;
40     case FD::FLOAT: *os << "float"; break;
41     case FD::STRING: *os << "char"; break;
42     case FD::BLOB: *os << "u8"; break;
43     default:
44         if (fd.type() & FD::STRUCT_FLAG) {
45             *os << "struct-" << (fd.type() & ~FD::STRUCT_FLAG);
46         } else {
47             *os << "type-" << fd.type();
48         }
49     }
50     *os << " " << fd.name();
51     if (fd.extent() > 1) {
52         *os << "[" << fd.extent() << "]";
53     } else if (fd.extent() == 0) {
54         *os << "[]";
55     }
56     *os << " (" << fd._mFieldId << "*" << fd.extent() << ")";
57 }
58 
59 C2ENUM(
60     MetadataType, int32_t,
61     kInvalid = -1,
62     kNone = 0,
63     kGralloc,
64     kNativeHandle,
65     kANativeWindow,
66     kCamera,
67 )
68 
69 enum {
70     kParamIndexVideoConfig = 0x1234,
71 };
72 
73 struct C2VideoConfigStruct {
74     int32_t width;
75     uint32_t height;
76     MetadataType metadataType;
77     int32_t supportedFormats[];
78 
C2VideoConfigStructC2VideoConfigStruct79     C2VideoConfigStruct() {}
80 
81     DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(VideoConfig, supportedFormats)
82     C2FIELD(width, "width")
83     C2FIELD(height, "height")
84     C2FIELD(metadataType, "metadata-type")
85     C2FIELD(supportedFormats, "formats")
86 };
87 
88 typedef C2PortParam<C2Tuning, C2VideoConfigStruct> C2VideoConfigPortTuning;
89 
90 class MyComponentInstance : public C2ComponentInterface {
91 public:
getName() const92     virtual C2String getName() const override {
93         /// \todo this seems too specific
94         return "sample.interface";
95     };
96 
getId() const97     virtual c2_node_id_t getId() const override {
98         /// \todo how are these shared?
99         return 0;
100     }
101 
config_vb(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)102     virtual c2_status_t config_vb(
103             const std::vector<C2Param*> &params,
104             c2_blocking_t mayBlock,
105             std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
106         (void)params;
107         (void)failures;
108         (void)mayBlock;
109         return C2_OMITTED;
110     }
111 
createTunnel_sm(c2_node_id_t targetComponent)112     virtual c2_status_t createTunnel_sm(c2_node_id_t targetComponent) override {
113         (void)targetComponent;
114         return C2_OMITTED;
115     }
116 
query_vb(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const117     virtual c2_status_t query_vb(
118             const std::vector<C2Param*> &stackParams,
119             const std::vector<C2Param::Index> &heapParamIndices,
120             c2_blocking_t mayBlock,
121             std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
122         for (C2Param* const param : stackParams) {
123             (void)mayBlock;
124             if (!*param) { // param is already invalid - remember it
125                 continue;
126             }
127 
128             // note: this does not handle stream params (should use index...)
129             if (!mMyParams.count(param->index())) {
130                 continue; // not my param
131             }
132 
133             C2Param & myParam = mMyParams.find(param->index())->second;
134             if (myParam.size() != param->size()) { // incorrect size
135                 param->invalidate();
136                 continue;
137             }
138 
139             param->updateFrom(myParam);
140         }
141 
142         for (const C2Param::Index index : heapParamIndices) {
143             if (mMyParams.count(index)) {
144                 C2Param & myParam = mMyParams.find(index)->second;
145                 std::unique_ptr<C2Param> paramCopy(C2Param::Copy(myParam));
146                 heapParams->push_back(std::move(paramCopy));
147             }
148         }
149 
150         return C2_OK;
151     }
152 
153     std::unordered_map<uint32_t, C2Param &> mMyParams;
154 
155     C2ComponentDomainSetting mDomainInfo;
156 
MyComponentInstance()157     MyComponentInstance() {
158         mMyParams.insert({mDomainInfo.index(), mDomainInfo});
159     }
160 
releaseTunnel_sm(c2_node_id_t targetComponent)161     virtual c2_status_t releaseTunnel_sm(c2_node_id_t targetComponent) override {
162         (void)targetComponent;
163         return C2_OMITTED;
164     }
165 
166     class MyParamReflector : public C2ParamReflector {
167         const MyComponentInstance *instance;
168 
169     public:
MyParamReflector(const MyComponentInstance * i)170         MyParamReflector(const MyComponentInstance *i) : instance(i) { }
171 
describe(C2Param::CoreIndex paramIndex) const172         virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex paramIndex) const override {
173             switch (paramIndex.typeIndex()) {
174             case decltype(instance->mDomainInfo)::CORE_INDEX:
175             default:
176                 return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor{
177                     instance->mDomainInfo.type(),
178                     decltype(instance->mDomainInfo)::FieldList(),
179                 });
180             }
181             return nullptr;
182         }
183     };
184 
querySupportedValues_vb(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const185     virtual c2_status_t querySupportedValues_vb(
186             std::vector<C2FieldSupportedValuesQuery> &fields,
187             c2_blocking_t mayBlock) const override {
188         (void)mayBlock;
189         for (C2FieldSupportedValuesQuery &query : fields) {
190             if (query.field() == C2ParamField(&mDomainInfo, &C2ComponentDomainSetting::value)) {
191                 query.values = C2FieldSupportedValues(
192                     false /* flag */,
193                     &mDomainInfo.value
194                     //,
195                     //{(int32_t)C2Component::DOMAIN_VIDEO}
196                 );
197                 query.status = C2_OK;
198             } else {
199                 query.status = C2_BAD_INDEX;
200             }
201         }
202         return C2_OK;
203     }
204 
getParamReflector() const205     std::shared_ptr<C2ParamReflector> getParamReflector() const {
206         return std::shared_ptr<C2ParamReflector>(new MyParamReflector(this));
207     }
208 
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const209     virtual c2_status_t querySupportedParams_nb(
210             std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override {
211         params->push_back(std::make_shared<C2ParamDescriptor>(
212                 true /* required */, "_domain", &mDomainInfo));
213         params->push_back(std::shared_ptr<C2ParamDescriptor>(
214                 new C2ParamDescriptor(true /* required */, "_domain", &mDomainInfo)));
215         return C2_OK;
216     }
217 
218     virtual ~MyComponentInstance() override = default;
219 };
220 
221 template<typename E, bool S=std::is_enum<E>::value>
222 struct getter {
getgetter223     int32_t get(const C2FieldSupportedValues::Primitive &p, int32_t*) {
224         return p.i32;
225     }
getgetter226     int64_t get(const C2FieldSupportedValues::Primitive &p, int64_t*) {
227         return p.i64;
228     }
getgetter229     uint32_t get(const C2FieldSupportedValues::Primitive &p, uint32_t*) {
230         return p.u32;
231     }
getgetter232     uint64_t get(const C2FieldSupportedValues::Primitive &p, uint64_t*) {
233         return p.u64;
234     }
getgetter235     float get(const C2FieldSupportedValues::Primitive &p, float*) {
236         return p.fp;
237     }
238 };
239 
240 template<typename E>
241 struct getter<E, true> {
getgetter242      typename std::underlying_type<E>::type get(const C2FieldSupportedValues::Primitive &p, E*) {
243          using u=typename std::underlying_type<E>::type;
244          return getter<u>().get(p, (u*)0);
245      }
246 };
247 
248 template<typename T, bool E=std::is_enum<T>::value>
249 struct lax_underlying_type {
250     typedef typename std::underlying_type<T>::type type;
251 };
252 
253 template<typename T>
254 struct lax_underlying_type<T, false> {
255     typedef T type;
256 };
257 
258 template<typename E>
get(const C2FieldSupportedValues::Primitive & p,E *)259 typename lax_underlying_type<E>::type get(
260         const C2FieldSupportedValues::Primitive &p, E*) {
261     return getter<E>().get(p, (E*)0);
262 }
263 
264 template<typename T>
dumpFSV(const C2FieldSupportedValues & sv,T * t)265 void dumpFSV(const C2FieldSupportedValues &sv, T*t) {
266     using namespace std;
267     cout << (std::is_enum<T>::value ? (std::is_signed<typename lax_underlying_type<T>::type>::value ? "i" : "u")
268              : std::is_integral<T>::value ? std::is_signed<T>::value ? "i" : "u" : "f")
269          << (8 * sizeof(T));
270     if (sv.type == sv.RANGE) {
271         cout << ".range(" << get(sv.range.min, t);
272         if (get(sv.range.step, t) != std::is_integral<T>::value) {
273             cout << ":" << get(sv.range.step, t);
274         }
275         if (get(sv.range.num, t) != 1 || get(sv.range.denom, t) != 1) {
276             cout << ":" << get(sv.range.num, t) << "/" << get(sv.range.denom, t);
277         }
278         cout << get(sv.range.max, t) << ")";
279     }
280     if (sv.values.size()) {
281         cout << (sv.type == sv.FLAGS ? ".flags(" : ".list(");
282         const char *sep = "";
283         for (const C2FieldSupportedValues::Primitive &p : sv.values) {
284             cout << sep << get(p, t);
285             sep = ",";
286         }
287         cout << ")";
288     }
289     cout << endl;
290 }
291 
dumpType(C2Param::Type type)292 void dumpType(C2Param::Type type) {
293     using namespace std;
294     cout << (type.isVendor() ? "Vendor" : "C2");
295     if (type.forInput()) {
296         cout << "Input";
297     } else if (type.forOutput()) {
298         cout << "Output";
299     } else if (type.forPort() && !type.forStream()) {
300         cout << "Port";
301     }
302     if (type.forStream()) {
303         cout << "Stream";
304     }
305 
306     if (type.isFlexible()) {
307         cout << "Flex";
308     }
309 
310     cout << type.typeIndex();
311 
312     switch (type.kind()) {
313     case C2Param::INFO: cout << "Info"; break;
314     case C2Param::SETTING: cout << "Setting"; break;
315     case C2Param::TUNING: cout << "Tuning"; break;
316     case C2Param::STRUCT: cout << "Struct"; break;
317     default: cout << "Kind" << (int32_t)type.kind(); break;
318     }
319 }
320 
dumpType(C2Param::CoreIndex type)321 void dumpType(C2Param::CoreIndex type) {
322     using namespace std;
323     cout << (type.isVendor() ? "Vendor" : "C2");
324     if (type.isFlexible()) {
325         cout << "Flex";
326     }
327 
328     cout << type.typeIndex() << "Struct";
329 }
330 
dumpType(C2FieldDescriptor::type_t type)331 void dumpType(C2FieldDescriptor::type_t type) {
332     using namespace std;
333     switch (type) {
334     case C2FieldDescriptor::BLOB: cout << "blob "; break;
335     case C2FieldDescriptor::FLOAT: cout << "float "; break;
336     case C2FieldDescriptor::INT32: cout << "int32_t "; break;
337     case C2FieldDescriptor::INT64: cout << "int64_t "; break;
338     case C2FieldDescriptor::UINT32: cout << "uint32_t "; break;
339     case C2FieldDescriptor::UINT64: cout << "uint64_t "; break;
340     case C2FieldDescriptor::STRING: cout << "char "; break;
341     default:
342         cout << "struct ";
343         dumpType((C2Param::Type)type);
344         break;
345     }
346 }
347 
dumpStruct(const C2StructDescriptor & sd)348 void dumpStruct(const C2StructDescriptor &sd) {
349     using namespace std;
350     cout << "struct ";
351     dumpType(sd.coreIndex());
352     cout << " {" << endl;
353     //C2FieldDescriptor &f;
354     for (const C2FieldDescriptor &f : sd) {
355         PrintTo(f, &cout);
356         cout << endl;
357 
358         if (f.namedValues().size()) {
359             cout << ".named(";
360             const char *sep = "";
361             for (const C2FieldDescriptor::NamedValueType &p : f.namedValues()) {
362                 cout << sep << p.first << "=";
363                 switch (f.type()) {
364                 case C2FieldDescriptor::INT32: cout << get(p.second, (int32_t *)0); break;
365                 case C2FieldDescriptor::INT64: cout << get(p.second, (int64_t *)0); break;
366                 case C2FieldDescriptor::UINT32: cout << get(p.second, (uint32_t *)0); break;
367                 case C2FieldDescriptor::UINT64: cout << get(p.second, (uint64_t *)0); break;
368                 case C2FieldDescriptor::FLOAT: cout << get(p.second, (float *)0); break;
369                 default: cout << "???"; break;
370                 }
371                 sep = ",";
372             }
373             cout << ")";
374         }
375     }
376 
377     cout << "};" << endl;
378 }
379 
dumpDesc(const C2ParamDescriptor & pd)380 void dumpDesc(const C2ParamDescriptor &pd) {
381     using namespace std;
382     if (pd.isRequired()) {
383         cout << "required ";
384     }
385     if (pd.isPersistent()) {
386         cout << "persistent ";
387     }
388     cout << "struct ";
389     dumpType(C2Param::Type(pd.index().type()));
390     cout << " " << pd.name() << ";" << endl;
391 }
392 
TEST_F(C2SampleComponentTest,ReflectorTest)393 TEST_F(C2SampleComponentTest, ReflectorTest) {
394     C2ComponentDomainSetting domainInfo;
395     std::shared_ptr<MyComponentInstance> myComp(new MyComponentInstance);
396     std::shared_ptr<C2ComponentInterface> comp = myComp;
397 
398     std::unique_ptr<C2StructDescriptor> desc{
399         myComp->getParamReflector()->describe(C2ComponentDomainSetting::CORE_INDEX)};
400     dumpStruct(*desc);
401 
402     std::vector<C2FieldSupportedValuesQuery> query = {
403         { C2ParamField(&domainInfo, &C2ComponentDomainSetting::value),
404           C2FieldSupportedValuesQuery::CURRENT },
405         C2FieldSupportedValuesQuery(C2ParamField(&domainInfo, &C2ComponentDomainSetting::value),
406           C2FieldSupportedValuesQuery::CURRENT),
407         C2FieldSupportedValuesQuery::Current(C2ParamField(&domainInfo, &C2ComponentDomainSetting::value)),
408     };
409 
410     EXPECT_EQ(C2_OK, comp->querySupportedValues_vb(query, C2_DONT_BLOCK));
411 
412     for (const C2FieldSupportedValuesQuery &q : query) {
413         dumpFSV(q.values, &domainInfo.value);
414     }
415 }
416 
TEST_F(C2SampleComponentTest,FieldSupportedValuesTest)417 TEST_F(C2SampleComponentTest, FieldSupportedValuesTest) {
418     typedef C2GlobalParam<C2Info, C2Uint32Value, 0> Uint32TestInfo;
419     Uint32TestInfo t;
420     std::vector<C2FieldSupportedValues> values;
421     values.push_back(C2FieldSupportedValues(0, 10, 1));  // min, max, step
422     values.push_back(C2FieldSupportedValues(1, 64, 2, 1));  // min, max, num, den
423     values.push_back(C2FieldSupportedValues(false, {1, 2, 3}));  // flags, std::initializer_list
424     uint32_t val[] = {1, 3, 5, 7};
425     std::vector<uint32_t> v(std::begin(val), std::end(val));
426     values.push_back(C2FieldSupportedValues(false, v));  // flags, std::vector
427 
428     for (const C2FieldSupportedValues &sv : values) {
429         dumpFSV(sv, &t.value);
430     }
431 }
432 
433