OSDN Git Service

build: autotools: don't check for X11 libraries
[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         , is_supported(true)
78         , surfaces() // empty
79         , coded(VA_INVALID_ID) // invalid
80         , renderBuffers() // empty
81         , input() // invalid
82         , output() // empty
83     { }
84
85 protected:
86     virtual void SetUp()
87     {
88         JPEGEncodeTest::SetUp();
89
90         struct i965_driver_data *i965(*this);
91         ASSERT_PTR(i965);
92
93         if (not HAS_JPEG_ENCODING(i965)) {
94             is_supported = false;
95             return;
96         }
97
98         TestInputCreator::SharedConst creator;
99         std::string sFourcc;
100         std::tie(creator, sFourcc) = GetParam();
101
102         ASSERT_PTR(creator.get()) << "Invalid test input creator parameter";
103
104         const std::array<unsigned, 2> res = creator->getResolution();
105         bool is_big_size = (res.at(0) > 4096) or (res.at(1) > 4096);
106         if (IS_CHERRYVIEW(i965->intel.device_info) and is_big_size) {
107             is_supported = false;
108             return;
109         }
110
111         ASSERT_EQ(4u, sFourcc.size())
112             << "Invalid fourcc parameter '" << sFourcc << "'";
113
114         unsigned fourcc = VA_FOURCC(
115             sFourcc[0], sFourcc[1], sFourcc[2], sFourcc[3]);
116
117         input = creator->create(fourcc);
118
119         ASSERT_PTR(input.get())
120             << "Unhandled fourcc parameter '" << sFourcc << "'"
121             << " = 0x" << std::hex << fourcc << std::dec;
122
123         ASSERT_EQ(fourcc, input->image->fourcc);
124
125         RecordProperty("test_input", toString(*input));
126     }
127
128     virtual void TearDown()
129     {
130         for (auto id : renderBuffers) {
131             if (id != VA_INVALID_ID) {
132                 destroyBuffer(id);
133             }
134         }
135         renderBuffers.clear();
136
137         if (coded != VA_INVALID_ID) {
138             destroyBuffer(coded);
139             coded = VA_INVALID_ID;
140         }
141
142         if (not surfaces.empty()) {
143             destroySurfaces(surfaces);
144             surfaces.clear();
145         }
146
147         if (std::get<0>(GetParam()).get())
148             std::cout << "Creator: " << std::get<0>(GetParam()) << std::endl;
149         if (input.get())
150             std::cout << "Input  : " << input << std::endl;
151
152         JPEGEncodeTest::TearDown();
153     }
154
155     void Encode()
156     {
157         ASSERT_FALSE(surfaces.empty());
158
159         ASSERT_NO_FAILURE(
160             beginPicture(context, surfaces.front()));
161         ASSERT_NO_FAILURE(
162             renderPicture(context, renderBuffers.data(), renderBuffers.size()));
163         ASSERT_NO_FAILURE(
164             endPicture(context));
165         ASSERT_NO_FAILURE(
166             syncSurface(surfaces.front()));
167         ASSERT_NO_FAILURE(
168             VACodedBufferSegment *segment =
169                 mapBuffer<VACodedBufferSegment>(coded));
170
171         EXPECT_FALSE(segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK)
172             << "segment->size = " << segment->size;
173         EXPECT_PTR_NULL(segment->next);
174
175         // copy segment buffer to output while stripping the packed header data
176         const size_t headerSize(1);
177         output.resize(segment->size - headerSize, 0x0);
178         std::memcpy(
179             output.data(),
180             reinterpret_cast<uint8_t *>(segment->buf) + headerSize,
181             segment->size - headerSize);
182
183         unmapBuffer(coded);
184
185         // EOI JPEG Marker
186         ASSERT_GE(output.size(), 2u);
187         EXPECT_TRUE(
188             unsigned(0xff) == unsigned(*(output.end() - 2)) and
189             unsigned(0xd9) == unsigned(output.back()))
190             << "Invalid JPEG EOI Marker";
191     }
192
193     void SetUpSurfaces()
194     {
195         SurfaceAttribs attributes(1);
196         attributes.front().flags = VA_SURFACE_ATTRIB_SETTABLE;
197         attributes.front().type = VASurfaceAttribPixelFormat;
198         attributes.front().value.type = VAGenericValueTypeInteger;
199         attributes.front().value.value.i = input->image->fourcc;
200         surfaces = createSurfaces(input->image->width, input->image->height,
201             input->image->format, 1, attributes);
202
203         ASSERT_EQ(1u, surfaces.size());
204         ASSERT_ID(surfaces.front());
205
206         input->image->toSurface(surfaces.front());
207     }
208
209     void SetUpConfig()
210     {
211         ASSERT_INVALID_ID(config);
212         ConfigAttribs attributes(
213             1, {type:VAConfigAttribRTFormat, value:input->image->format});
214         config = createConfig(profile, entrypoint, attributes);
215     }
216
217     void SetUpContext()
218     {
219         ASSERT_INVALID_ID(context);
220         context = createContext(config, input->image->width,
221             input->image->height, 0, surfaces);
222     }
223
224     void SetUpCodedBuffer()
225     {
226         ASSERT_INVALID_ID(coded);
227         unsigned size = input->image->sizes.sum() + 8192u;
228         size *= 2;
229         coded = createBuffer(context, VAEncCodedBufferType, size);
230     }
231
232     void SetUpPicture()
233     {
234         input->picture.coded_buf = coded;
235         renderBuffers.push_back(
236             createBuffer(context, VAEncPictureParameterBufferType,
237                 sizeof(PictureParameter), 1, &input->picture));
238     }
239
240     void SetUpIQMatrix()
241     {
242         renderBuffers.push_back(
243             createBuffer(context, VAQMatrixBufferType, sizeof(IQMatrix),
244                 1, &input->matrix));
245     }
246
247     void SetUpHuffmanTables()
248     {
249         renderBuffers.push_back(
250             createBuffer(context, VAHuffmanTableBufferType,
251                 sizeof(HuffmanTable), 1, &input->huffman));
252     }
253
254     void SetUpSlice()
255     {
256         renderBuffers.push_back(
257             createBuffer(context, VAEncSliceParameterBufferType,
258                 sizeof(SliceParameter), 1, &input->slice));
259     }
260
261     void SetUpHeader()
262     {
263         /*
264          * The driver expects a packed JPEG header which it prepends to the
265          * coded buffer segment output. The driver does not appear to inspect
266          * this header, however.  So we'll just create a 1-byte packed header
267          * since we really don't care if it contains a "valid" JPEG header.
268          */
269         renderBuffers.push_back(
270             createBuffer(context, VAEncPackedHeaderParameterBufferType,
271                 sizeof(VAEncPackedHeaderParameterBuffer)));
272         if (HasFailure())
273             return;
274
275         VAEncPackedHeaderParameterBuffer *packed =
276             mapBuffer<VAEncPackedHeaderParameterBuffer>(renderBuffers.back());
277         if (HasFailure())
278             return;
279
280         std::memset(packed, 0, sizeof(*packed));
281         packed->type = VAEncPackedHeaderRawData;
282         packed->bit_length = 8;
283         packed->has_emulation_bytes = 0;
284
285         unmapBuffer(renderBuffers.back());
286
287         renderBuffers.push_back(
288             createBuffer(context, VAEncPackedHeaderDataBufferType, 1));
289     }
290
291     bool                is_supported;
292     Surfaces            surfaces;
293     VABufferID          coded;
294     Buffers             renderBuffers;
295     TestInput::Shared   input;
296     ByteData            output;
297
298     void VerifyOutput()
299     {
300         YUVImage::SharedConst expect = input->toExpectedOutput();
301         ASSERT_PTR(expect.get());
302
303         ::JPEG::Decode::PictureData::SharedConst pd =
304             ::JPEG::Decode::PictureData::make(
305                 expect->fourcc, output, expect->width, expect->height);
306
307         ASSERT_PTR(pd.get());
308
309         ASSERT_NO_FAILURE(
310             Surfaces osurfaces = createSurfaces(
311                 pd->pparam.picture_width, pd->pparam.picture_height,
312                 pd->format));;
313
314         ConfigAttribs attribs(
315             1, {type:VAConfigAttribRTFormat, value:pd->format});
316         ASSERT_NO_FAILURE(
317             VAConfigID oconfig = createConfig(
318                 ::JPEG::profile, ::JPEG::Decode::entrypoint, attribs));
319
320         ASSERT_NO_FAILURE(
321             VAContextID ocontext = createContext(
322                 oconfig, pd->pparam.picture_width, pd->pparam.picture_height,
323                 0, osurfaces));
324
325         Buffers buffers;
326
327         ASSERT_NO_FAILURE(
328             buffers.push_back(
329                 createBuffer(
330                     ocontext, VASliceDataBufferType, pd->sparam.slice_data_size,
331                     1, pd->slice.data())));
332
333         ASSERT_NO_FAILURE(
334             buffers.push_back(
335                 createBuffer(
336                     ocontext, VASliceParameterBufferType, sizeof(pd->sparam),
337                     1, &pd->sparam)));
338
339         ASSERT_NO_FAILURE(
340             buffers.push_back(
341                 createBuffer(
342                     ocontext,VAPictureParameterBufferType, sizeof(pd->pparam),
343                     1, &pd->pparam)));
344
345         ASSERT_NO_FAILURE(
346             buffers.push_back(
347                 createBuffer(
348                     ocontext, VAIQMatrixBufferType, sizeof(pd->iqmatrix),
349                     1, &pd->iqmatrix)));
350
351         ASSERT_NO_FAILURE(
352             buffers.push_back(
353                 createBuffer(
354                     ocontext, VAHuffmanTableBufferType, sizeof(pd->huffman),
355                     1, &pd->huffman)));
356
357         ASSERT_NO_FAILURE(beginPicture(ocontext, osurfaces.front()));
358         ASSERT_NO_FAILURE(
359             renderPicture(ocontext, buffers.data(), buffers.size()));
360         ASSERT_NO_FAILURE(endPicture(ocontext));
361         ASSERT_NO_FAILURE(syncSurface(osurfaces.front()));
362
363         ASSERT_NO_FAILURE(
364             YUVImage::Shared result = YUVImage::create(osurfaces.front()));
365         ASSERT_PTR(result.get());
366         ASSERT_EQ(expect->planes, result->planes);
367         ASSERT_EQ(expect->width, result->width);
368         ASSERT_EQ(expect->height, result->height);
369         ASSERT_TRUE((result->widths == expect->widths).min());
370         ASSERT_TRUE((result->heights == expect->heights).min());
371         ASSERT_TRUE((result->offsets == expect->offsets).min());
372         ASSERT_TRUE((result->sizes == expect->sizes).min());
373         ASSERT_EQ(expect->bytes.size(), result->bytes.size());
374
375         std::valarray<int16_t> rbytes(result->bytes.size());
376         std::copy(std::begin(result->bytes), std::end(result->bytes),
377             std::begin(rbytes));
378
379         std::valarray<int16_t> ebytes(expect->bytes.size());
380         std::copy(std::begin(expect->bytes), std::end(expect->bytes),
381             std::begin(ebytes));
382
383         EXPECT_TRUE(std::abs(ebytes - rbytes).max() <= 2);
384         if (HasFailure()) {
385             std::valarray<int16_t> r = std::abs(ebytes - rbytes);
386             for (size_t i(0); i < expect->planes; ++i) {
387                 std::valarray<int16_t> plane = r[expect->slices[i]];
388                 size_t mismatch = std::count_if(
389                     std::begin(plane), std::end(plane),
390                     [](const uint16_t& v){return v > 2;});
391                 std::cout << "\tplane " << i << ": "
392                     << mismatch << " of " << plane.size()
393                     << " (" << (float(mismatch) / plane.size() * 100)
394                     << "%) mismatch" << std::endl;
395             }
396         }
397
398         for (auto id : buffers)
399             destroyBuffer(id);
400
401         destroyContext(ocontext);
402         destroyConfig(oconfig);
403         destroySurfaces(osurfaces);
404     }
405 };
406
407 TEST_P(JPEGEncodeInputTest, Full)
408 {
409     if (not is_supported) {
410         RecordProperty("skipped", true);
411         std::cout << "[  SKIPPED ] " << getFullTestName()
412             << " is unsupported on this hardware" << std::endl;
413         return;
414     }
415
416     ASSERT_NO_FAILURE(SetUpSurfaces());
417     ASSERT_NO_FAILURE(SetUpConfig());
418     ASSERT_NO_FAILURE(SetUpContext());
419     ASSERT_NO_FAILURE(SetUpCodedBuffer());
420     ASSERT_NO_FAILURE(SetUpPicture());
421     ASSERT_NO_FAILURE(SetUpIQMatrix());
422     ASSERT_NO_FAILURE(SetUpHuffmanTables());
423     ASSERT_NO_FAILURE(SetUpSlice());
424     ASSERT_NO_FAILURE(SetUpHeader());
425     ASSERT_NO_FAILURE(Encode());
426
427     VerifyOutput();
428 }
429
430 INSTANTIATE_TEST_CASE_P(
431     Random, JPEGEncodeInputTest,
432     ::testing::Combine(
433         ::testing::ValuesIn(
434             std::vector<TestInputCreator::SharedConst>(
435                 5, TestInputCreator::SharedConst(new RandomSizeCreator))),
436         ::testing::Values("I420", "NV12", "UYVY", "YUY2", "Y800")
437     )
438 );
439
440 InputCreators generateCommonInputs()
441 {
442     return {
443         TestInputCreator::Shared(new FixedSizeCreator({800, 600})), /* SVGA */
444         TestInputCreator::Shared(new FixedSizeCreator({1024, 600})), /* WSVGA */
445         TestInputCreator::Shared(new FixedSizeCreator({1024, 768})), /* XGA */
446         TestInputCreator::Shared(new FixedSizeCreator({1152, 864})), /* XGA+ */
447         TestInputCreator::Shared(new FixedSizeCreator({1280, 720})), /* WXGA */
448         TestInputCreator::Shared(new FixedSizeCreator({1280, 768})), /* WXGA */
449         TestInputCreator::Shared(new FixedSizeCreator({1280, 800})), /* WXGA */
450         TestInputCreator::Shared(new FixedSizeCreator({1280, 1024})), /* SXGA */
451         TestInputCreator::Shared(new FixedSizeCreator({1360, 768})), /* HD */
452         TestInputCreator::Shared(new FixedSizeCreator({1366, 768})), /* HD */
453         TestInputCreator::Shared(new FixedSizeCreator({1440, 900})), /* WXGA+ */
454         TestInputCreator::Shared(new FixedSizeCreator({1600, 900})), /* HD+ */
455         TestInputCreator::Shared(new FixedSizeCreator({1600, 1200})), /* UXGA */
456         TestInputCreator::Shared(new FixedSizeCreator({1680, 1050})), /* WSXGA+ */
457         TestInputCreator::Shared(new FixedSizeCreator({1920, 1080})), /* FHD */
458         TestInputCreator::Shared(new FixedSizeCreator({1920, 1200})), /* WUXGA */
459         TestInputCreator::Shared(new FixedSizeCreator({2560, 1440})), /* WQHD */
460         TestInputCreator::Shared(new FixedSizeCreator({2560, 1600})), /* WQXGA */
461         TestInputCreator::Shared(new FixedSizeCreator({3640, 2160})), /* UHD (4K) */
462         TestInputCreator::Shared(new FixedSizeCreator({7680, 4320})), /* UHD (8K) */
463     };
464 }
465
466 INSTANTIATE_TEST_CASE_P(
467     Common, JPEGEncodeInputTest,
468     ::testing::Combine(
469         ::testing::ValuesIn(generateCommonInputs()),
470         ::testing::Values("I420", "NV12", "UYVY", "YUY2", "Y800")
471     )
472 );
473
474 INSTANTIATE_TEST_CASE_P(
475     Big, JPEGEncodeInputTest,
476     ::testing::Combine(
477         ::testing::Values(
478             TestInputCreator::Shared(new FixedSizeCreator({8192, 8192}))
479         ),
480         ::testing::Values("I420", "NV12", "UYVY", "YUY2", "Y800")
481     )
482 );
483
484 InputCreators generateEdgeCaseInputs()
485 {
486     std::vector<TestInputCreator::SharedConst> result;
487     for (unsigned i(64); i <= 512; i += 64) {
488         result.push_back(
489             TestInputCreator::Shared(new FixedSizeCreator({i, i})));
490         result.push_back(
491             TestInputCreator::Shared(new FixedSizeCreator({i+1, i})));
492         result.push_back(
493             TestInputCreator::Shared(new FixedSizeCreator({i, i+1})));
494         result.push_back(
495             TestInputCreator::Shared(new FixedSizeCreator({i+1, i+1})));
496         result.push_back(
497             TestInputCreator::Shared(new FixedSizeCreator({i-1, i})));
498         result.push_back(
499             TestInputCreator::Shared(new FixedSizeCreator({i, i-1})));
500         result.push_back(
501             TestInputCreator::Shared(new FixedSizeCreator({i-1, i-1})));
502     }
503
504     result.push_back(TestInputCreator::Shared(new FixedSizeCreator({1, 1})));
505     result.push_back(TestInputCreator::Shared(new FixedSizeCreator({1, 2})));
506     result.push_back(TestInputCreator::Shared(new FixedSizeCreator({2, 1})));
507     result.push_back(TestInputCreator::Shared(new FixedSizeCreator({2, 2})));
508     result.push_back(TestInputCreator::Shared(new FixedSizeCreator({1, 462})));
509
510     return result;
511 }
512
513 INSTANTIATE_TEST_CASE_P(
514     Edge, JPEGEncodeInputTest,
515     ::testing::Combine(
516         ::testing::ValuesIn(generateEdgeCaseInputs()),
517         ::testing::Values("I420", "NV12", "UYVY", "YUY2", "Y800")
518     )
519 );
520
521 InputCreators generateMiscInputs()
522 {
523     return {
524         TestInputCreator::Shared(new FixedSizeCreator({150, 75})),
525         TestInputCreator::Shared(new FixedSizeCreator({10, 10})),
526         TestInputCreator::Shared(new FixedSizeCreator({385, 610})),
527         TestInputCreator::Shared(new FixedSizeCreator({1245, 1281})),
528     };
529 }
530
531 INSTANTIATE_TEST_CASE_P(
532     Misc, JPEGEncodeInputTest,
533     ::testing::Combine(
534         ::testing::ValuesIn(generateMiscInputs()),
535         ::testing::Values("I420", "NV12", "UYVY", "YUY2", "Y800")
536     )
537 );
538
539 } // namespace Encode
540 } // namespace JPEG