OSDN Git Service

test: check whether MVC encoding is support
[android-x86/hardware-intel-common-vaapi.git] / test / i965_jpeg_encode_test.cpp
1 /*
2  * Copyright (C) 2016 Intel Corporation. All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sub license, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial portions
14  * of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 #include "i965_jpeg_test_data.h"
26 #include "i965_streamable.h"
27 #include "i965_test_fixture.h"
28 #include "test_utils.h"
29
30 #include <numeric>
31 #include <cstring>
32 #include <memory>
33 #include <tuple>
34 #include <valarray>
35
36 namespace JPEG {
37 namespace Encode {
38
39 class JPEGEncodeTest
40     : public I965TestFixture
41 {
42 public:
43     JPEGEncodeTest()
44         : I965TestFixture()
45         , config(VA_INVALID_ID) // invalid
46         , context(VA_INVALID_ID) // invalid
47     { }
48
49 protected:
50     virtual void TearDown()
51     {
52         if (context != VA_INVALID_ID) {
53             destroyContext(context);
54             context = VA_INVALID_ID;
55         }
56
57         if (config != VA_INVALID_ID) {
58             destroyConfig(config);
59             config = VA_INVALID_ID;
60         }
61
62         I965TestFixture::TearDown();
63     }
64
65     VAConfigID config;
66     VAContextID context;
67 };
68
69 class JPEGEncodeInputTest
70     : public JPEGEncodeTest
71     , public ::testing::WithParamInterface<
72         std::tuple<TestInputCreator::SharedConst, const char*> >
73 {
74 public:
75     JPEGEncodeInputTest()
76         : JPEGEncodeTest::JPEGEncodeTest()
77         , surfaces() // empty
78         , coded(VA_INVALID_ID) // invalid
79         , renderBuffers() // empty
80         , input() // invalid
81         , output() // empty
82     { }
83
84 protected:
85     virtual void SetUp()
86     {
87         JPEGEncodeTest::SetUp();
88
89         struct i965_driver_data *i965(*this);
90         ASSERT_PTR(i965);
91         if (not HAS_JPEG_ENCODING(i965))
92             return;
93
94         TestInputCreator::SharedConst creator;
95         std::string sFourcc;
96         std::tie(creator, sFourcc) = GetParam();
97
98         ASSERT_PTR(creator.get()) << "Invalid test input creator parameter";
99
100         ASSERT_EQ(4u, sFourcc.size())
101             << "Invalid fourcc parameter '" << sFourcc << "'";
102
103         unsigned fourcc = VA_FOURCC(
104             sFourcc[0], sFourcc[1], sFourcc[2], sFourcc[3]);
105
106         input = creator->create(fourcc);
107
108         ASSERT_PTR(input.get())
109             << "Unhandled fourcc parameter '" << sFourcc << "'"
110             << " = 0x" << std::hex << fourcc << std::dec;
111
112         ASSERT_EQ(fourcc, input->image->fourcc);
113
114         RecordProperty("test_input", toString(*input));
115     }
116
117     virtual void TearDown()
118     {
119         for (auto id : renderBuffers) {
120             if (id != VA_INVALID_ID) {
121                 destroyBuffer(id);
122             }
123         }
124         renderBuffers.clear();
125
126         if (coded != VA_INVALID_ID) {
127             destroyBuffer(coded);
128             coded = VA_INVALID_ID;
129         }
130
131         if (not surfaces.empty()) {
132             destroySurfaces(surfaces);
133             surfaces.clear();
134         }
135
136         if (std::get<0>(GetParam()).get())
137             std::cout << "Creator: " << std::get<0>(GetParam()) << std::endl;
138         if (input.get())
139             std::cout << "Input  : " << input << std::endl;
140
141         JPEGEncodeTest::TearDown();
142     }
143
144     void Encode()
145     {
146         ASSERT_FALSE(surfaces.empty());
147
148         ASSERT_NO_FAILURE(
149             beginPicture(context, surfaces.front()));
150         ASSERT_NO_FAILURE(
151             renderPicture(context, renderBuffers.data(), renderBuffers.size()));
152         ASSERT_NO_FAILURE(
153             endPicture(context));
154         ASSERT_NO_FAILURE(
155             syncSurface(surfaces.front()));
156         ASSERT_NO_FAILURE(
157             VACodedBufferSegment *segment =
158                 mapBuffer<VACodedBufferSegment>(coded));
159
160         EXPECT_FALSE(segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK)
161             << "segment->size = " << segment->size;
162         EXPECT_PTR_NULL(segment->next);
163
164         // copy segment buffer to output while stripping the packed header data
165         const size_t headerSize(1);
166         output.resize(segment->size - headerSize, 0x0);
167         std::memcpy(
168             output.data(),
169             reinterpret_cast<uint8_t *>(segment->buf) + headerSize,
170             segment->size - headerSize);
171
172         unmapBuffer(coded);
173
174         // EOI JPEG Marker
175         ASSERT_GE(output.size(), 2u);
176         EXPECT_TRUE(
177             unsigned(0xff) == unsigned(*(output.end() - 2)) and
178             unsigned(0xd9) == unsigned(output.back()))
179             << "Invalid JPEG EOI Marker";
180     }
181
182     void SetUpSurfaces()
183     {
184         SurfaceAttribs attributes(1);
185         attributes.front().flags = VA_SURFACE_ATTRIB_SETTABLE;
186         attributes.front().type = VASurfaceAttribPixelFormat;
187         attributes.front().value.type = VAGenericValueTypeInteger;
188         attributes.front().value.value.i = input->image->fourcc;
189         surfaces = createSurfaces(input->image->width, input->image->height,
190             input->image->format, 1, attributes);
191
192         ASSERT_EQ(1u, surfaces.size());
193         ASSERT_ID(surfaces.front());
194
195         input->image->toSurface(surfaces.front());
196     }
197
198     void SetUpConfig()
199     {
200         ASSERT_INVALID_ID(config);
201         ConfigAttribs attributes(
202             1, {type:VAConfigAttribRTFormat, value:input->image->format});
203         config = createConfig(profile, entrypoint, attributes);
204     }
205
206     void SetUpContext()
207     {
208         ASSERT_INVALID_ID(context);
209         context = createContext(config, input->image->width,
210             input->image->height, 0, surfaces);
211     }
212
213     void SetUpCodedBuffer()
214     {
215         ASSERT_INVALID_ID(coded);
216         unsigned size = input->image->sizes.sum() + 8192u;
217         size *= 2;
218         coded = createBuffer(context, VAEncCodedBufferType, size);
219     }
220
221     void SetUpPicture()
222     {
223         input->picture.coded_buf = coded;
224         renderBuffers.push_back(
225             createBuffer(context, VAEncPictureParameterBufferType,
226                 sizeof(PictureParameter), 1, &input->picture));
227     }
228
229     void SetUpIQMatrix()
230     {
231         renderBuffers.push_back(
232             createBuffer(context, VAQMatrixBufferType, sizeof(IQMatrix),
233                 1, &input->matrix));
234     }
235
236     void SetUpHuffmanTables()
237     {
238         renderBuffers.push_back(
239             createBuffer(context, VAHuffmanTableBufferType,
240                 sizeof(HuffmanTable), 1, &input->huffman));
241     }
242
243     void SetUpSlice()
244     {
245         renderBuffers.push_back(
246             createBuffer(context, VAEncSliceParameterBufferType,
247                 sizeof(SliceParameter), 1, &input->slice));
248     }
249
250     void SetUpHeader()
251     {
252         /*
253          * The driver expects a packed JPEG header which it prepends to the
254          * coded buffer segment output. The driver does not appear to inspect
255          * this header, however.  So we'll just create a 1-byte packed header
256          * since we really don't care if it contains a "valid" JPEG header.
257          */
258         renderBuffers.push_back(
259             createBuffer(context, VAEncPackedHeaderParameterBufferType,
260                 sizeof(VAEncPackedHeaderParameterBuffer)));
261         if (HasFailure())
262             return;
263
264         VAEncPackedHeaderParameterBuffer *packed =
265             mapBuffer<VAEncPackedHeaderParameterBuffer>(renderBuffers.back());
266         if (HasFailure())
267             return;
268
269         std::memset(packed, 0, sizeof(*packed));
270         packed->type = VAEncPackedHeaderRawData;
271         packed->bit_length = 8;
272         packed->has_emulation_bytes = 0;
273
274         unmapBuffer(renderBuffers.back());
275
276         renderBuffers.push_back(
277             createBuffer(context, VAEncPackedHeaderDataBufferType, 1));
278     }
279
280     Surfaces            surfaces;
281     VABufferID          coded;
282     Buffers             renderBuffers;
283     TestInput::Shared   input;
284     ByteData            output;
285
286     void VerifyOutput()
287     {
288         YUVImage::SharedConst expect = input->toExpectedOutput();
289         ASSERT_PTR(expect.get());
290
291         ::JPEG::Decode::PictureData::SharedConst pd =
292             ::JPEG::Decode::PictureData::make(
293                 expect->fourcc, output, expect->width, expect->height);
294
295         ASSERT_PTR(pd.get());
296
297         ASSERT_NO_FAILURE(
298             Surfaces osurfaces = createSurfaces(
299                 pd->pparam.picture_width, pd->pparam.picture_height,
300                 pd->format));;
301
302         ConfigAttribs attribs(
303             1, {type:VAConfigAttribRTFormat, value:pd->format});
304         ASSERT_NO_FAILURE(
305             VAConfigID oconfig = createConfig(
306                 ::JPEG::profile, ::JPEG::Decode::entrypoint, attribs));
307
308         ASSERT_NO_FAILURE(
309             VAContextID ocontext = createContext(
310                 oconfig, pd->pparam.picture_width, pd->pparam.picture_height,
311                 0, osurfaces));
312
313         Buffers buffers;
314
315         ASSERT_NO_FAILURE(
316             buffers.push_back(
317                 createBuffer(
318                     ocontext, VASliceDataBufferType, pd->sparam.slice_data_size,
319                     1, pd->slice.data())));
320
321         ASSERT_NO_FAILURE(
322             buffers.push_back(
323                 createBuffer(
324                     ocontext, VASliceParameterBufferType, sizeof(pd->sparam),
325                     1, &pd->sparam)));
326
327         ASSERT_NO_FAILURE(
328             buffers.push_back(
329                 createBuffer(
330                     ocontext,VAPictureParameterBufferType, sizeof(pd->pparam),
331                     1, &pd->pparam)));
332
333         ASSERT_NO_FAILURE(
334             buffers.push_back(
335                 createBuffer(
336                     ocontext, VAIQMatrixBufferType, sizeof(pd->iqmatrix),
337                     1, &pd->iqmatrix)));
338
339         ASSERT_NO_FAILURE(
340             buffers.push_back(
341                 createBuffer(
342                     ocontext, VAHuffmanTableBufferType, sizeof(pd->huffman),
343                     1, &pd->huffman)));
344
345         ASSERT_NO_FAILURE(beginPicture(ocontext, osurfaces.front()));
346         ASSERT_NO_FAILURE(
347             renderPicture(ocontext, buffers.data(), buffers.size()));
348         ASSERT_NO_FAILURE(endPicture(ocontext));
349         ASSERT_NO_FAILURE(syncSurface(osurfaces.front()));
350
351         ASSERT_NO_FAILURE(
352             YUVImage::Shared result = YUVImage::create(osurfaces.front()));
353         ASSERT_PTR(result.get());
354         ASSERT_EQ(expect->planes, result->planes);
355         ASSERT_EQ(expect->width, result->width);
356         ASSERT_EQ(expect->height, result->height);
357         ASSERT_TRUE((result->widths == expect->widths).min());
358         ASSERT_TRUE((result->heights == expect->heights).min());
359         ASSERT_TRUE((result->offsets == expect->offsets).min());
360         ASSERT_TRUE((result->sizes == expect->sizes).min());
361         ASSERT_EQ(expect->bytes.size(), result->bytes.size());
362
363         std::valarray<int16_t> rbytes(result->bytes.size());
364         std::copy(std::begin(result->bytes), std::end(result->bytes),
365             std::begin(rbytes));
366
367         std::valarray<int16_t> ebytes(expect->bytes.size());
368         std::copy(std::begin(expect->bytes), std::end(expect->bytes),
369             std::begin(ebytes));
370
371         EXPECT_TRUE(std::abs(ebytes - rbytes).max() <= 2);
372         if (HasFailure()) {
373             std::valarray<int16_t> r = std::abs(ebytes - rbytes);
374             for (size_t i(0); i < expect->planes; ++i) {
375                 std::valarray<int16_t> plane = r[expect->slices[i]];
376                 size_t mismatch = std::count_if(
377                     std::begin(plane), std::end(plane),
378                     [](const uint16_t& v){return v > 2;});
379                 std::cout << "\tplane " << i << ": "
380                     << mismatch << " of " << plane.size()
381                     << " (" << (float(mismatch) / plane.size() * 100)
382                     << "%) mismatch" << std::endl;
383             }
384         }
385
386         for (auto id : buffers)
387             destroyBuffer(id);
388
389         destroyContext(ocontext);
390         destroyConfig(oconfig);
391         destroySurfaces(osurfaces);
392     }
393 };
394
395 TEST_P(JPEGEncodeInputTest, Full)
396 {
397     struct i965_driver_data *i965(*this);
398     ASSERT_PTR(i965);
399     if (not HAS_JPEG_ENCODING(i965)) {
400         RecordProperty("skipped", true);
401         std::cout << "[  SKIPPED ] " << getFullTestName()
402             << " is unsupported on this hardware" << std::endl;
403         return;
404     }
405
406     ASSERT_NO_FAILURE(SetUpSurfaces());
407     ASSERT_NO_FAILURE(SetUpConfig());
408     ASSERT_NO_FAILURE(SetUpContext());
409     ASSERT_NO_FAILURE(SetUpCodedBuffer());
410     ASSERT_NO_FAILURE(SetUpPicture());
411     ASSERT_NO_FAILURE(SetUpIQMatrix());
412     ASSERT_NO_FAILURE(SetUpHuffmanTables());
413     ASSERT_NO_FAILURE(SetUpSlice());
414     ASSERT_NO_FAILURE(SetUpHeader());
415     ASSERT_NO_FAILURE(Encode());
416
417     VerifyOutput();
418 }
419
420 INSTANTIATE_TEST_CASE_P(
421     Random, JPEGEncodeInputTest,
422     ::testing::Combine(
423         ::testing::ValuesIn(
424             std::vector<TestInputCreator::SharedConst>(
425                 5, TestInputCreator::SharedConst(new RandomSizeCreator))),
426         ::testing::Values("I420", "NV12", "UYVY", "YUY2", "Y800")
427     )
428 );
429
430 InputCreators generateCommonInputs()
431 {
432     return {
433         TestInputCreator::Shared(new FixedSizeCreator({800, 600})), /* SVGA */
434         TestInputCreator::Shared(new FixedSizeCreator({1024, 600})), /* WSVGA */
435         TestInputCreator::Shared(new FixedSizeCreator({1024, 768})), /* XGA */
436         TestInputCreator::Shared(new FixedSizeCreator({1152, 864})), /* XGA+ */
437         TestInputCreator::Shared(new FixedSizeCreator({1280, 720})), /* WXGA */
438         TestInputCreator::Shared(new FixedSizeCreator({1280, 768})), /* WXGA */
439         TestInputCreator::Shared(new FixedSizeCreator({1280, 800})), /* WXGA */
440         TestInputCreator::Shared(new FixedSizeCreator({1280, 1024})), /* SXGA */
441         TestInputCreator::Shared(new FixedSizeCreator({1360, 768})), /* HD */
442         TestInputCreator::Shared(new FixedSizeCreator({1366, 768})), /* HD */
443         TestInputCreator::Shared(new FixedSizeCreator({1440, 900})), /* WXGA+ */
444         TestInputCreator::Shared(new FixedSizeCreator({1600, 900})), /* HD+ */
445         TestInputCreator::Shared(new FixedSizeCreator({1600, 1200})), /* UXGA */
446         TestInputCreator::Shared(new FixedSizeCreator({1680, 1050})), /* WSXGA+ */
447         TestInputCreator::Shared(new FixedSizeCreator({1920, 1080})), /* FHD */
448         TestInputCreator::Shared(new FixedSizeCreator({1920, 1200})), /* WUXGA */
449         TestInputCreator::Shared(new FixedSizeCreator({2560, 1440})), /* WQHD */
450         TestInputCreator::Shared(new FixedSizeCreator({2560, 1600})), /* WQXGA */
451         TestInputCreator::Shared(new FixedSizeCreator({3640, 2160})), /* UHD (4K) */
452         TestInputCreator::Shared(new FixedSizeCreator({7680, 4320})), /* UHD (8K) */
453     };
454 }
455
456 INSTANTIATE_TEST_CASE_P(
457     Common, JPEGEncodeInputTest,
458     ::testing::Combine(
459         ::testing::ValuesIn(generateCommonInputs()),
460         ::testing::Values("I420", "NV12", "UYVY", "YUY2", "Y800")
461     )
462 );
463
464 INSTANTIATE_TEST_CASE_P(
465     Big, JPEGEncodeInputTest,
466     ::testing::Combine(
467         ::testing::Values(
468             TestInputCreator::Shared(new FixedSizeCreator({8192, 8192}))
469         ),
470         ::testing::Values("I420", "NV12", "UYVY", "YUY2", "Y800")
471     )
472 );
473
474 InputCreators generateEdgeCaseInputs()
475 {
476     std::vector<TestInputCreator::SharedConst> result;
477     for (unsigned i(64); i <= 512; i += 64) {
478         result.push_back(
479             TestInputCreator::Shared(new FixedSizeCreator({i, i})));
480         result.push_back(
481             TestInputCreator::Shared(new FixedSizeCreator({i+1, i})));
482         result.push_back(
483             TestInputCreator::Shared(new FixedSizeCreator({i, i+1})));
484         result.push_back(
485             TestInputCreator::Shared(new FixedSizeCreator({i+1, i+1})));
486         result.push_back(
487             TestInputCreator::Shared(new FixedSizeCreator({i-1, i})));
488         result.push_back(
489             TestInputCreator::Shared(new FixedSizeCreator({i, i-1})));
490         result.push_back(
491             TestInputCreator::Shared(new FixedSizeCreator({i-1, i-1})));
492     }
493
494     result.push_back(TestInputCreator::Shared(new FixedSizeCreator({1, 1})));
495     result.push_back(TestInputCreator::Shared(new FixedSizeCreator({1, 2})));
496     result.push_back(TestInputCreator::Shared(new FixedSizeCreator({2, 1})));
497     result.push_back(TestInputCreator::Shared(new FixedSizeCreator({2, 2})));
498     result.push_back(TestInputCreator::Shared(new FixedSizeCreator({1, 462})));
499
500     return result;
501 }
502
503 INSTANTIATE_TEST_CASE_P(
504     Edge, JPEGEncodeInputTest,
505     ::testing::Combine(
506         ::testing::ValuesIn(generateEdgeCaseInputs()),
507         ::testing::Values("I420", "NV12", "UYVY", "YUY2", "Y800")
508     )
509 );
510
511 InputCreators generateMiscInputs()
512 {
513     return {
514         TestInputCreator::Shared(new FixedSizeCreator({150, 75})),
515         TestInputCreator::Shared(new FixedSizeCreator({10, 10})),
516         TestInputCreator::Shared(new FixedSizeCreator({385, 610})),
517         TestInputCreator::Shared(new FixedSizeCreator({1245, 1281})),
518     };
519 }
520
521 INSTANTIATE_TEST_CASE_P(
522     Misc, JPEGEncodeInputTest,
523     ::testing::Combine(
524         ::testing::ValuesIn(generateMiscInputs()),
525         ::testing::Values("I420", "NV12", "UYVY", "YUY2", "Y800")
526     )
527 );
528
529 } // namespace Encode
530 } // namespace JPEG