• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "test_va_api_fixture.h"
26 
27 #include <algorithm>
28 #include <functional>
29 
30 #include <fcntl.h> // for O_RDWR
31 #include <limits>
32 #include <string.h>
33 
34 #if defined(_WIN32)
35 #include <va/va_win32.h>
36 #include <compat_win32.h>
37 #else
38 #include <unistd.h> // for close()
39 #include <va/va_drm.h>
40 #include <xf86drm.h>
41 #endif
42 
43 namespace VAAPI
44 {
45 
46 int VAAPIFixtureSharedDisplay::s_drmHandle = -1;
47 VADisplay VAAPIFixtureSharedDisplay::s_vaDisplay = nullptr;
48 VAStatus VAAPIFixtureSharedDisplay::s_initStatus = VA_STATUS_SUCCESS;
49 
VAAPIFixture()50 VAAPIFixture::VAAPIFixture()
51     : ::testing::Test::Test()
52     , m_vaDisplay(NULL)
53     , m_drmHandle(-1)
54     , m_configID(VA_INVALID_ID)
55     , m_contextID(VA_INVALID_ID)
56     , m_bufferID(VA_INVALID_ID)
57     , m_skip("")
58 {
59     // If we do not copy the value and use the same pointer returned by getenv to restore the value
60     // in ~VAAPIFixture with setenv, we see garbage memory being set on Windows platforms.
61     char* libva_driver = getenv("LIBVA_DRIVER_NAME");
62     if (libva_driver) m_restoreDriverName = libva_driver;
63 }
64 
~VAAPIFixture()65 VAAPIFixture::~VAAPIFixture()
66 {
67     m_vaDisplay = NULL;
68     if (m_drmHandle >= 0)
69         close(m_drmHandle);
70     m_drmHandle = -1;
71 
72     // Ensure LIBVA_DRIVER_NAME environment is restored to its original
73     // setting so successive tests use the expected driver.
74     unsetenv("LIBVA_DRIVER_NAME");
75     if (!m_restoreDriverName.empty())
76         setenv("LIBVA_DRIVER_NAME", m_restoreDriverName.c_str(), 1);
77 
78     if (!m_skip.empty()) {
79         EXPECT_FALSE(HasFailure())
80                 << "skip message is set, but something failed";
81         if (!HasFailure()) {
82             RecordProperty("skipped", true);
83             std::cout << "[ SKIPPED ] " << m_skip << std::endl;
84         }
85     }
86 }
87 
88 #if defined(_WIN32)
getWin32Display(LUID * adapter)89 static VADisplay getWin32Display(LUID* adapter)
90 {
91     return vaGetDisplayWin32(adapter);
92 }
93 #else
getDrmDisplay(int & fd)94 static VADisplay getDrmDisplay(int &fd)
95 {
96     drmDevicePtr devices[32];
97     int ret, max_devices = sizeof(devices) / sizeof(devices[0]);
98 
99     ret = drmGetDevices2(0, devices, max_devices);
100     EXPECT_TRUE(ret >= 0);
101     if (ret < 0)
102         return NULL;
103     max_devices = ret;
104 
105     for (int i = 0; i < max_devices; i++) {
106         for (int j = DRM_NODE_MAX - 1; j >= 0; j--) {
107             drmVersionPtr version;
108 
109             if (!(devices[i]->available_nodes & 1 << j))
110                 continue;
111 
112             fd = open(devices[i]->nodes[j], O_RDWR);
113             if (fd < 0)
114                 continue;
115 
116             version = drmGetVersion(fd);
117             if (!version) {
118                 close(fd);
119                 continue;
120             }
121             if (!strncmp(version->name, "vgem", 4)) {
122                 drmFreeVersion(version);
123                 close(fd);
124                 continue;
125             }
126             drmFreeVersion(version);
127 
128             VADisplay disp = vaGetDisplayDRM(fd);
129 
130             if (disp)
131                 return disp;
132 
133             close(fd);
134         }
135     }
136 
137     return NULL;
138 }
139 #endif
getDisplay()140 VADisplay VAAPIFixture::getDisplay()
141 {
142 #if defined(_WIN32)
143     m_vaDisplay = getWin32Display(NULL);
144 #else
145     m_vaDisplay = getDrmDisplay(m_drmHandle);
146 #endif
147     return m_vaDisplay;
148 }
149 
doInitialize()150 VADisplay VAAPIFixture::doInitialize()
151 {
152     VADisplay vaDisplay;
153     VAStatus status;
154     int majorVersion, minorVersion;
155 
156     vaDisplay = getDisplay();
157     EXPECT_TRUE(vaDisplay);
158     if (!vaDisplay) {
159         return NULL;
160     }
161 
162     status = vaInitialize(vaDisplay, &majorVersion, &minorVersion);
163     EXPECT_STATUS(status) << "failed to initialize vaapi";
164     if (status != VA_STATUS_SUCCESS) {
165         return NULL;
166     }
167 
168     return vaDisplay;
169 }
170 
queryConfigProfiles(Profiles & profiles) const171 void VAAPIFixture::queryConfigProfiles(Profiles& profiles) const
172 {
173     const int maxProfiles = vaMaxNumProfiles(m_vaDisplay);
174     ASSERT_GT(maxProfiles, 0);
175     profiles.resize(maxProfiles);
176 
177     int numProfiles(0);
178     EXPECT_STATUS(
179         vaQueryConfigProfiles(m_vaDisplay, profiles.data(), &numProfiles));
180 
181     if (!HasFailure()) {
182         ASSERT_LE(numProfiles, maxProfiles);
183         ASSERT_GT(numProfiles, 0);
184         profiles.resize(numProfiles);
185     } else {
186         profiles.clear();
187     }
188 }
189 
queryConfigEntrypoints(const VAProfile & profile,Entrypoints & entrypoints,const VAStatus & expectation) const190 void VAAPIFixture::queryConfigEntrypoints(const VAProfile& profile,
191         Entrypoints& entrypoints, const VAStatus& expectation) const
192 {
193     const int maxEntrypoints = vaMaxNumEntrypoints(m_vaDisplay);
194     ASSERT_GT(maxEntrypoints, 0);
195     entrypoints.resize(maxEntrypoints);
196 
197     int numEntrypoints(0);
198     EXPECT_STATUS_EQ(
199         expectation,
200         vaQueryConfigEntrypoints(m_vaDisplay, profile, entrypoints.data(),
201                                  &numEntrypoints));
202 
203     if ((VA_STATUS_SUCCESS == expectation) && !HasFailure()) {
204         ASSERT_LE(numEntrypoints, maxEntrypoints);
205         ASSERT_GT(numEntrypoints, 0);
206         entrypoints.resize(numEntrypoints);
207     } else {
208         entrypoints.clear();
209     }
210 }
211 
getSupportStatus(const VAProfile & profile,const VAEntrypoint & entrypoint) const212 VAStatus VAAPIFixture::getSupportStatus(const VAProfile& profile,
213                                         const VAEntrypoint& entrypoint) const
214 {
215     Profiles profiles;
216     queryConfigProfiles(profiles);
217 
218     const auto pBegin(profiles.begin());
219     const auto pEnd(profiles.end());
220     if (std::find(pBegin, pEnd, profile) != pEnd) {
221         Entrypoints entrypoints;
222         queryConfigEntrypoints(profile, entrypoints);
223 
224         const auto eBegin(entrypoints.begin());
225         const auto eEnd(entrypoints.end());
226         return (std::find(eBegin, eEnd, entrypoint) != eEnd) ?
227                VA_STATUS_SUCCESS : VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
228     }
229 
230     return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
231 }
232 
isSupported(const VAProfile & profile,const VAEntrypoint & entrypoint) const233 bool VAAPIFixture::isSupported(const VAProfile& profile,
234                                const VAEntrypoint& entrypoint) const
235 {
236     return VA_STATUS_SUCCESS == getSupportStatus(profile, entrypoint);
237 }
238 
getConfigAttributes(const VAProfile & profile,const VAEntrypoint & entrypoint,ConfigAttributes & attribs,const VAStatus & expectation) const239 void VAAPIFixture::getConfigAttributes(const VAProfile& profile,
240                                        const VAEntrypoint& entrypoint, ConfigAttributes& attribs,
241                                        const VAStatus& expectation) const
242 {
243     const bool defaults(attribs.empty());
244 
245     if (defaults) {
246         // fill config attributes with default config attributes
247         const auto op = [](const VAConfigAttribType & t) {
248             return VAConfigAttrib{/*type:*/ t, /*value:*/ VA_ATTRIB_NOT_SUPPORTED};
249         };
250         std::transform(g_vaConfigAttribTypes.begin(),
251                        g_vaConfigAttribTypes.end(), std::back_inserter(attribs), op);
252     }
253 
254     ASSERT_FALSE(attribs.empty());
255 
256     EXPECT_STATUS_EQ(
257         expectation,
258         vaGetConfigAttributes(
259             m_vaDisplay, profile, entrypoint, attribs.data(), attribs.size()));
260 
261     if (defaults) {
262         // remove unsupported config attributes
263         const auto begin(attribs.begin());
264         const auto end(attribs.end());
265         const auto predicate = [](const VAConfigAttrib & a) {
266             return a.value == VA_ATTRIB_NOT_SUPPORTED;
267         };
268         attribs.erase(std::remove_if(begin, end, predicate), end);
269     }
270 }
271 
createConfig(const VAProfile & profile,const VAEntrypoint & entrypoint,const ConfigAttributes & attribs,const VAStatus & expectation)272 void VAAPIFixture::createConfig(const VAProfile& profile,
273                                 const VAEntrypoint& entrypoint, const ConfigAttributes& attribs,
274                                 const VAStatus& expectation)
275 {
276     ASSERT_INVALID_ID(m_configID)
277             << "test logic error: did you forget to call destroyConfig?";
278 
279     EXPECT_STATUS_EQ(
280         expectation,
281         vaCreateConfig(m_vaDisplay, profile, entrypoint,
282                        (attribs.size() != 0 ?
283                         const_cast<VAConfigAttrib*>(attribs.data()) : NULL),
284                        attribs.size(), &m_configID))
285             << "profile    = " << profile << std::endl
286             << "entrypoint = " << entrypoint << std::endl
287             << "numAttribs = " << attribs.size();
288 
289     if (expectation == VA_STATUS_SUCCESS) {
290         EXPECT_ID(m_configID);
291     } else {
292         EXPECT_INVALID_ID(m_configID);
293     }
294 }
295 
queryConfigAttributes(const VAProfile & expectedProfile,const VAEntrypoint & expectedEntrypoint,ConfigAttributes & attributes,const VAStatus & expectedStatus) const296 void VAAPIFixture::queryConfigAttributes(
297     const VAProfile& expectedProfile, const VAEntrypoint& expectedEntrypoint,
298     ConfigAttributes& attributes, const VAStatus& expectedStatus) const
299 {
300     VAProfile actualProfile;
301     VAEntrypoint actualEntrypoint;
302     int numAttributes(0);
303 
304     ASSERT_TRUE(attributes.empty())
305             << "test logic error: attributes must be empty";
306 
307     const int maxAttributes = vaMaxNumConfigAttributes(m_vaDisplay);
308 
309     ASSERT_GT(maxAttributes, 0);
310 
311     attributes.resize(maxAttributes);
312 
313     EXPECT_STATUS_EQ(
314         expectedStatus,
315         vaQueryConfigAttributes(m_vaDisplay, m_configID, &actualProfile,
316                                 &actualEntrypoint, attributes.data(), &numAttributes));
317 
318     if (expectedStatus == VA_STATUS_SUCCESS) {
319         EXPECT_EQ(expectedProfile, actualProfile);
320         EXPECT_EQ(expectedEntrypoint, actualEntrypoint);
321         ASSERT_LE(numAttributes, maxAttributes);
322         ASSERT_GT(numAttributes, 0);
323 
324         attributes.resize(numAttributes);
325 
326         // reported config attributes should be supported
327         for (const auto& attribute : attributes) {
328             EXPECT_NE(VA_ATTRIB_NOT_SUPPORTED, attribute.value);
329         }
330     } else {
331         attributes.clear();
332     }
333 }
334 
destroyConfig(const VAStatus & expectation)335 void VAAPIFixture::destroyConfig(const VAStatus& expectation)
336 {
337     EXPECT_STATUS_EQ(expectation, vaDestroyConfig(m_vaDisplay, m_configID));
338     m_configID = VA_INVALID_ID;
339 }
340 
querySurfaceAttributes(SurfaceAttributes & attribs) const341 void VAAPIFixture::querySurfaceAttributes(SurfaceAttributes& attribs) const
342 {
343     ASSERT_TRUE(attribs.empty())
344             << "test logic error: surface attributes must be empty";
345 
346     unsigned numAttribs(0);
347 
348     ASSERT_STATUS(vaQuerySurfaceAttributes(m_vaDisplay, m_configID, NULL,
349                                            &numAttribs));
350 
351     ASSERT_GT(numAttribs, 0u);
352 
353     attribs.resize(numAttribs);
354 
355     ASSERT_STATUS(vaQuerySurfaceAttributes(m_vaDisplay, m_configID,
356                                            attribs.data(), &numAttribs));
357 
358     ASSERT_GT(numAttribs, 0u);
359     EXPECT_GE(attribs.size(), numAttribs);
360 
361     attribs.resize(numAttribs);
362 
363     const uint32_t flags = 0x0 | VA_SURFACE_ATTRIB_GETTABLE
364                            | VA_SURFACE_ATTRIB_SETTABLE;
365 
366     for (const auto& attrib : attribs) {
367         EXPECT_NE(attrib.flags & flags,
368                   (uint32_t)VA_SURFACE_ATTRIB_NOT_SUPPORTED);
369         EXPECT_GE(attrib.value.type, VAGenericValueTypeInteger);
370         EXPECT_LE(attrib.value.type, VAGenericValueTypeFunc);
371     }
372 }
373 
getMinMaxSurfaceResolution(Resolution & minRes,Resolution & maxRes) const374 void VAAPIFixture::getMinMaxSurfaceResolution(
375     Resolution& minRes, Resolution& maxRes) const
376 {
377     const Resolution::DataType maxVal =
378         std::numeric_limits<Resolution::DataType>::max();
379 
380     // set default resolutions
381     minRes.width = 1;
382     minRes.height = 1;
383     maxRes.width = maxVal;
384     maxRes.height = maxVal;
385 
386     SurfaceAttributes attribs;
387     querySurfaceAttributes(attribs);
388 
389     SurfaceAttributes::const_iterator match;
390     const SurfaceAttributes::const_iterator begin(attribs.begin());
391     const SurfaceAttributes::const_iterator end(attribs.end());
392 
393     // minimum surface width
394     match = std::find_if(begin, end, [](const VASurfaceAttrib & a) {
395         return a.type == VASurfaceAttribMinWidth;
396     });
397     if (match != end) {
398         EXPECT_EQ(VAGenericValueTypeInteger, match->value.type);
399         ASSERT_GE(match->value.value.i, 1);
400         ASSERT_LE((Resolution::DataType)match->value.value.i, maxVal);
401         minRes.width = match->value.value.i;
402     }
403 
404     // minimum surface height
405     match = std::find_if(begin, end, [](const VASurfaceAttrib & a) {
406         return a.type == VASurfaceAttribMinHeight;
407     });
408     if (match != end) {
409         EXPECT_EQ(VAGenericValueTypeInteger, match->value.type);
410         ASSERT_GE(match->value.value.i, 1);
411         ASSERT_LE((Resolution::DataType)match->value.value.i, maxVal);
412         minRes.height = match->value.value.i;
413     }
414 
415     // maximum surface width
416     match = std::find_if(begin, end, [](const VASurfaceAttrib & a) {
417         return a.type == VASurfaceAttribMaxWidth;
418     });
419     if (match != end) {
420         EXPECT_EQ(VAGenericValueTypeInteger, match->value.type);
421         ASSERT_GE(match->value.value.i, 1);
422         ASSERT_LE((Resolution::DataType)match->value.value.i, maxVal);
423         maxRes.width = match->value.value.i;
424     }
425 
426     // maximum surface height
427     match = std::find_if(begin, end, [](const VASurfaceAttrib & a) {
428         return a.type == VASurfaceAttribMaxHeight;
429     });
430     if (match != end) {
431         EXPECT_EQ(VAGenericValueTypeInteger, match->value.type);
432         ASSERT_GE(match->value.value.i, 1);
433         ASSERT_LE((Resolution::DataType)match->value.value.i, maxVal);
434         maxRes.height = match->value.value.i;
435     }
436 
437     EXPECT_LE(minRes, maxRes);
438 }
439 
createSurfaces(Surfaces & surfaces,const unsigned format,const Resolution & resolution,const SurfaceAttributes & attribs,const VAStatus & expectation) const440 void VAAPIFixture::createSurfaces(Surfaces& surfaces, const unsigned format,
441                                   const Resolution& resolution, const SurfaceAttributes& attribs,
442                                   const VAStatus& expectation) const
443 {
444     ASSERT_GT(surfaces.size(), 0u)
445             << "test logic error: surfaces must not be emtpy";
446     for (const auto& surface : surfaces) {
447         ASSERT_INVALID_ID(surface)
448                 << "test logic error: surfaces must all be VA_INVALID_SURFACE";
449     }
450 
451     ASSERT_STATUS_EQ(
452         expectation,
453         vaCreateSurfaces(m_vaDisplay, format, resolution.width,
454                          resolution.height, surfaces.data(), surfaces.size(),
455                          (attribs.size() != 0 ?
456                           const_cast<VASurfaceAttrib*>(attribs.data()) : NULL),
457                          attribs.size()));
458 
459     if (expectation == VA_STATUS_SUCCESS) {
460         for (const auto& surface : surfaces) {
461             ASSERT_ID(surface);
462         }
463     }
464 }
465 
destroySurfaces(Surfaces & surfaces) const466 void VAAPIFixture::destroySurfaces(Surfaces& surfaces) const
467 {
468     if (surfaces.size() != 0) {
469         EXPECT_STATUS(vaDestroySurfaces(m_vaDisplay, surfaces.data(),
470                                         surfaces.size()));
471     }
472 }
473 
createBuffer(const VABufferType & bufferType,const size_t bufferSize,const VAStatus & expectation)474 void VAAPIFixture::createBuffer(const VABufferType& bufferType,
475                                 const size_t bufferSize, const VAStatus& expectation)
476 {
477     ASSERT_INVALID_ID(m_bufferID)
478             << "test logic error: did you forget to call destroyBuffer?";
479 
480     EXPECT_STATUS_EQ(
481         expectation,
482         vaCreateBuffer(m_vaDisplay, m_contextID, bufferType, bufferSize,
483                        1, NULL, &m_bufferID));
484 }
485 
destroyBuffer(const VAStatus & expectation)486 void VAAPIFixture::destroyBuffer(const VAStatus& expectation)
487 {
488     EXPECT_STATUS_EQ(expectation, vaDestroyBuffer(m_vaDisplay, m_bufferID));
489     m_bufferID = VA_INVALID_ID;
490 }
491 
doCreateContext(const Resolution & resolution,const VAStatus & expectation)492 void VAAPIFixture::doCreateContext(const Resolution& resolution,
493                                    const VAStatus& expectation)
494 {
495     m_contextID = 0;
496     ASSERT_STATUS_EQ(expectation,
497                      vaCreateContext(m_vaDisplay, m_configID, resolution.width,
498                                      resolution.height, VA_PROGRESSIVE,
499                                      NULL, 0, &m_contextID));
500 }
501 
doDestroyContext(const VAStatus & expectation)502 void VAAPIFixture::doDestroyContext(const VAStatus& expectation)
503 {
504     ASSERT_STATUS_EQ(expectation, vaDestroyContext(m_vaDisplay, m_contextID));
505 }
506 
doTerminate()507 void VAAPIFixture::doTerminate()
508 {
509     EXPECT_STATUS(vaTerminate(m_vaDisplay));
510 }
511 
skipTest(const std::string & message)512 void VAAPIFixture::skipTest(const std::string& message)
513 {
514     ASSERT_FALSE(message.empty())
515             << "test logic error: skip message cannot be empty";
516     ASSERT_TRUE(m_skip.empty())
517             << "test logic error: test already marked as skipped";
518 
519     m_skip = message;
520 }
521 
skipTest(const VAProfile & profile,const VAEntrypoint & entrypoint)522 void VAAPIFixture::skipTest(const VAProfile& profile,
523                             const VAEntrypoint& entrypoint)
524 {
525     std::ostringstream oss;
526     oss << profile << " / " << entrypoint << " not supported on this hardware";
527     skipTest(oss.str());
528 }
529 
TEST_F(VAAPIFixture,getDisplay)530 TEST_F(VAAPIFixture, getDisplay)
531 {
532     VADisplay vaDisplay;
533 
534     vaDisplay = getDisplay();
535     ASSERT_TRUE(vaDisplay);
536     EXPECT_STATUS(vaTerminate(vaDisplay));
537 }
538 
VAAPIFixtureSharedDisplay()539 VAAPIFixtureSharedDisplay::VAAPIFixtureSharedDisplay() : VAAPIFixture() { }
540 
SetUpTestSuite()541 void VAAPIFixtureSharedDisplay::SetUpTestSuite()
542 {
543     if (s_drmHandle < 0) {
544 #if defined(_WIN32)
545         s_vaDisplay = getWin32Display(NULL);
546 #else
547         s_vaDisplay = getDrmDisplay(s_drmHandle);
548 #endif
549         int majorVersion, minorVersion;
550         s_initStatus = vaInitialize(s_vaDisplay, &majorVersion, &minorVersion);
551     }
552 }
553 
TearDownTestSuite()554 void VAAPIFixtureSharedDisplay::TearDownTestSuite()
555 {
556     if (s_vaDisplay) {
557         if (s_initStatus == VA_STATUS_SUCCESS) {
558             vaTerminate(s_vaDisplay);
559             s_vaDisplay = nullptr;
560         } else {
561             s_initStatus = VA_STATUS_SUCCESS;
562         }
563     }
564     if (s_drmHandle >= 0) {
565         close(s_drmHandle);
566         s_drmHandle = -1;
567     }
568 }
569 
SetUp()570 void VAAPIFixtureSharedDisplay::SetUp()
571 {
572     EXPECT_STATUS(s_initStatus) << "failed to initialize vaapi";
573 
574     m_vaDisplay = s_vaDisplay;
575 }
576 
577 } // namespace VAAPI
578