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*> ¶ms,
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 C2ComponentDomainInfo 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, &C2ComponentDomainInfo::value)) {
191 query.values = C2FieldSupportedValues(
192 false /* flag */,
193 &mDomainInfo.value
194 //,
195 //{(int32_t)C2DomainVideo}
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 C2ComponentDomainInfo 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(C2ComponentDomainInfo::CORE_INDEX)};
400 dumpStruct(*desc);
401
402 std::vector<C2FieldSupportedValuesQuery> query = {
403 { C2ParamField(&domainInfo, &C2ComponentDomainInfo::value),
404 C2FieldSupportedValuesQuery::CURRENT },
405 C2FieldSupportedValuesQuery(C2ParamField(&domainInfo, &C2ComponentDomainInfo::value),
406 C2FieldSupportedValuesQuery::CURRENT),
407 C2FieldSupportedValuesQuery::Current(C2ParamField(&domainInfo, &C2ComponentDomainInfo::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