blob: a0eafa6b155707e9e74bbba7a10fdac1b8e545af [file] [log] [blame]
/*
* Copyright (C) 2016 Intel Corporation. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "test_va_api_fixture.h"
#include <algorithm>
#include <functional>
#include <fcntl.h> // for O_RDWR
#include <limits>
#include <unistd.h> // for close()
#include <va/va_drm.h>
namespace VAAPI {
VAAPIFixture::VAAPIFixture()
: ::testing::Test::Test()
, m_vaDisplay(NULL)
, m_restoreDriverName(getenv("LIBVA_DRIVER_NAME"))
, m_drmHandle(-1)
, m_configID(VA_INVALID_ID)
, m_contextID(VA_INVALID_ID)
, m_bufferID(VA_INVALID_ID)
, m_skip("")
{
return;
}
VAAPIFixture::~VAAPIFixture()
{
m_vaDisplay = NULL;
if (m_drmHandle >= 0)
close(m_drmHandle);
m_drmHandle = -1;
// Ensure LIBVA_DRIVER_NAME environment is restored to its original
// setting so successive tests use the expected driver.
unsetenv("LIBVA_DRIVER_NAME");
if (m_restoreDriverName)
setenv("LIBVA_DRIVER_NAME", m_restoreDriverName, 1);
if (not m_skip.empty()) {
EXPECT_FALSE(HasFailure())
<< "skip message is set, but something failed";
if (not HasFailure()) {
RecordProperty("skipped", true);
std::cout << "[ SKIPPED ] " << m_skip << std::endl;
}
}
}
VADisplay VAAPIFixture::getDisplay()
{
typedef std::vector<std::string> DevicePaths;
typedef DevicePaths::const_iterator DevicePathsIterator;
static DevicePaths paths({"/dev/dri/renderD128", "/dev/dri/card0"});
const DevicePathsIterator endIt(paths.end());
for (DevicePathsIterator it(paths.begin()); it != endIt; ++it) {
m_drmHandle = open(it->c_str(), O_RDWR);
if (m_drmHandle < 0)
continue;
m_vaDisplay = vaGetDisplayDRM(m_drmHandle);
if (m_vaDisplay)
return m_vaDisplay;
}
return NULL;
}
VADisplay VAAPIFixture::doInitialize()
{
VADisplay vaDisplay;
VAStatus status;
int majorVersion, minorVersion;
vaDisplay = getDisplay();
EXPECT_TRUE(vaDisplay);
if (!vaDisplay) {
return NULL;
}
status = vaInitialize(vaDisplay, &majorVersion, &minorVersion);
EXPECT_STATUS(status) << "failed to initialize vaapi";
if (status != VA_STATUS_SUCCESS) {
return NULL;
}
return vaDisplay;
}
void VAAPIFixture::queryConfigProfiles(Profiles& profiles) const
{
const int maxProfiles = vaMaxNumProfiles(m_vaDisplay);
ASSERT_GT(maxProfiles, 0);
profiles.resize(maxProfiles);
int numProfiles(0);
EXPECT_STATUS(
vaQueryConfigProfiles(m_vaDisplay, profiles.data(), &numProfiles));
if (not HasFailure()) {
ASSERT_LE(numProfiles, maxProfiles);
ASSERT_GT(numProfiles, 0);
profiles.resize(numProfiles);
} else {
profiles.clear();
}
}
void VAAPIFixture::queryConfigEntrypoints(const VAProfile& profile,
Entrypoints& entrypoints, const VAStatus& expectation) const
{
const int maxEntrypoints = vaMaxNumEntrypoints(m_vaDisplay);
ASSERT_GT(maxEntrypoints, 0);
entrypoints.resize(maxEntrypoints);
int numEntrypoints(0);
EXPECT_STATUS_EQ(
expectation,
vaQueryConfigEntrypoints(m_vaDisplay, profile, entrypoints.data(),
&numEntrypoints));
if ((VA_STATUS_SUCCESS == expectation) and not HasFailure()) {
ASSERT_LE(numEntrypoints, maxEntrypoints);
ASSERT_GT(numEntrypoints, 0);
entrypoints.resize(numEntrypoints);
} else {
entrypoints.clear();
}
}
VAStatus VAAPIFixture::getSupportStatus(const VAProfile& profile,
const VAEntrypoint& entrypoint) const
{
Profiles profiles;
queryConfigProfiles(profiles);
const auto pBegin(profiles.begin());
const auto pEnd(profiles.end());
if (std::find(pBegin, pEnd, profile) != pEnd) {
Entrypoints entrypoints;
queryConfigEntrypoints(profile, entrypoints);
const auto eBegin(entrypoints.begin());
const auto eEnd(entrypoints.end());
return (std::find(eBegin, eEnd, entrypoint) != eEnd) ?
VA_STATUS_SUCCESS : VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
}
return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
}
bool VAAPIFixture::isSupported(const VAProfile& profile,
const VAEntrypoint& entrypoint) const
{
return VA_STATUS_SUCCESS == getSupportStatus(profile, entrypoint);
}
void VAAPIFixture::getConfigAttributes(const VAProfile& profile,
const VAEntrypoint& entrypoint, ConfigAttributes& attribs,
const VAStatus& expectation) const
{
const bool defaults(attribs.empty());
if (defaults) {
// fill config attributes with default config attributes
const auto op = [](const VAConfigAttribType& t) {
return VAConfigAttrib{type: t, value: VA_ATTRIB_NOT_SUPPORTED};
};
std::transform(g_vaConfigAttribTypes.begin(),
g_vaConfigAttribTypes.end(), std::back_inserter(attribs), op);
}
ASSERT_FALSE(attribs.empty());
EXPECT_STATUS_EQ(
expectation,
vaGetConfigAttributes(
m_vaDisplay, profile, entrypoint, attribs.data(), attribs.size()));
if (defaults) {
// remove unsupported config attributes
const auto begin(attribs.begin());
const auto end(attribs.end());
const auto predicate = [](const VAConfigAttrib& a) {
return a.value == VA_ATTRIB_NOT_SUPPORTED;
};
attribs.erase(std::remove_if(begin, end, predicate), end);
}
}
void VAAPIFixture::createConfig(const VAProfile& profile,
const VAEntrypoint& entrypoint, const ConfigAttributes& attribs,
const VAStatus& expectation)
{
ASSERT_INVALID_ID(m_configID)
<< "test logic error: did you forget to call destroyConfig?";
EXPECT_STATUS_EQ(
expectation,
vaCreateConfig(m_vaDisplay, profile, entrypoint,
(attribs.size() != 0 ?
const_cast<VAConfigAttrib*>(attribs.data()) : NULL),
attribs.size(), &m_configID))
<< "profile = " << profile << std::endl
<< "entrypoint = " << entrypoint << std::endl
<< "numAttribs = " << attribs.size();
if (expectation == VA_STATUS_SUCCESS) {
EXPECT_ID(m_configID);
} else {
EXPECT_INVALID_ID(m_configID);
}
}
void VAAPIFixture::queryConfigAttributes(
const VAProfile& expectedProfile, const VAEntrypoint& expectedEntrypoint,
ConfigAttributes& attributes, const VAStatus& expectedStatus) const
{
VAProfile actualProfile;
VAEntrypoint actualEntrypoint;
int numAttributes(0);
ASSERT_TRUE(attributes.empty())
<< "test logic error: attributes must be empty";
const int maxAttributes = vaMaxNumConfigAttributes(m_vaDisplay);
ASSERT_GT(maxAttributes, 0);
attributes.resize(maxAttributes);
EXPECT_STATUS_EQ(
expectedStatus,
vaQueryConfigAttributes(m_vaDisplay, m_configID, &actualProfile,
&actualEntrypoint, attributes.data(), &numAttributes));
if (expectedStatus == VA_STATUS_SUCCESS) {
EXPECT_EQ(expectedProfile, actualProfile);
EXPECT_EQ(expectedEntrypoint, actualEntrypoint);
ASSERT_LE(numAttributes, maxAttributes);
ASSERT_GT(numAttributes, 0);
attributes.resize(numAttributes);
// reported config attributes should be supported
for (const auto& attribute : attributes) {
EXPECT_NE(VA_ATTRIB_NOT_SUPPORTED, attribute.value);
}
} else {
attributes.clear();
}
}
void VAAPIFixture::destroyConfig(const VAStatus& expectation)
{
EXPECT_STATUS_EQ(expectation, vaDestroyConfig(m_vaDisplay, m_configID));
m_configID = VA_INVALID_ID;
}
void VAAPIFixture::querySurfaceAttributes(SurfaceAttributes& attribs) const
{
ASSERT_TRUE(attribs.empty())
<< "test logic error: surface attributes must be empty";
unsigned numAttribs(0);
ASSERT_STATUS(vaQuerySurfaceAttributes(m_vaDisplay, m_configID, NULL,
&numAttribs));
ASSERT_GT(numAttribs, 0u);
attribs.resize(numAttribs);
ASSERT_STATUS(vaQuerySurfaceAttributes(m_vaDisplay, m_configID,
attribs.data(), &numAttribs));
ASSERT_GT(numAttribs, 0u);
EXPECT_GE(attribs.size(), numAttribs);
attribs.resize(numAttribs);
const uint32_t flags = 0x0 | VA_SURFACE_ATTRIB_GETTABLE
| VA_SURFACE_ATTRIB_SETTABLE;
for (const auto& attrib : attribs) {
EXPECT_NE(attrib.flags & flags,
(uint32_t)VA_SURFACE_ATTRIB_NOT_SUPPORTED);
EXPECT_GE(attrib.value.type, VAGenericValueTypeInteger);
EXPECT_LE(attrib.value.type, VAGenericValueTypeFunc);
}
}
void VAAPIFixture::getMinMaxSurfaceResolution(
Resolution& minRes, Resolution& maxRes) const
{
const Resolution::DataType maxVal =
std::numeric_limits<Resolution::DataType>::max();
// set default resolutions
minRes.width = 1;
minRes.height = 1;
maxRes.width = maxVal;
maxRes.height = maxVal;
SurfaceAttributes attribs;
querySurfaceAttributes(attribs);
SurfaceAttributes::const_iterator match;
const SurfaceAttributes::const_iterator begin(attribs.begin());
const SurfaceAttributes::const_iterator end(attribs.end());
// minimum surface width
match = std::find_if(begin, end, [](const VASurfaceAttrib& a)
{return a.type == VASurfaceAttribMinWidth;});
if (match != end) {
EXPECT_EQ(VAGenericValueTypeInteger, match->value.type);
ASSERT_GE(match->value.value.i, 1);
ASSERT_LE((Resolution::DataType)match->value.value.i, maxVal);
minRes.width = match->value.value.i;
}
// minimum surface height
match = std::find_if(begin, end, [](const VASurfaceAttrib& a)
{return a.type == VASurfaceAttribMinHeight;});
if (match != end) {
EXPECT_EQ(VAGenericValueTypeInteger, match->value.type);
ASSERT_GE(match->value.value.i, 1);
ASSERT_LE((Resolution::DataType)match->value.value.i, maxVal);
minRes.height = match->value.value.i;
}
// maximum surface width
match = std::find_if(begin, end, [](const VASurfaceAttrib& a)
{return a.type == VASurfaceAttribMaxWidth;});
if (match != end) {
EXPECT_EQ(VAGenericValueTypeInteger, match->value.type);
ASSERT_GE(match->value.value.i, 1);
ASSERT_LE((Resolution::DataType)match->value.value.i, maxVal);
maxRes.width = match->value.value.i;
}
// maximum surface height
match = std::find_if(begin, end, [](const VASurfaceAttrib& a)
{return a.type == VASurfaceAttribMaxHeight;});
if (match != end) {
EXPECT_EQ(VAGenericValueTypeInteger, match->value.type);
ASSERT_GE(match->value.value.i, 1);
ASSERT_LE((Resolution::DataType)match->value.value.i, maxVal);
maxRes.height = match->value.value.i;
}
EXPECT_LE(minRes, maxRes);
}
void VAAPIFixture::createSurfaces(Surfaces& surfaces, const unsigned format,
const Resolution& resolution, const SurfaceAttributes& attribs,
const VAStatus& expectation) const
{
ASSERT_GT(surfaces.size(), 0u)
<< "test logic error: surfaces must not be emtpy";
for (const auto& surface : surfaces) {
ASSERT_INVALID_ID(surface)
<< "test logic error: surfaces must all be VA_INVALID_SURFACE";
}
ASSERT_STATUS_EQ(
expectation,
vaCreateSurfaces(m_vaDisplay, format, resolution.width,
resolution.height, surfaces.data(), surfaces.size(),
(attribs.size() != 0 ?
const_cast<VASurfaceAttrib*>(attribs.data()) : NULL),
attribs.size()));
if (expectation == VA_STATUS_SUCCESS) {
for (const auto& surface : surfaces) {
ASSERT_ID(surface);
}
}
}
void VAAPIFixture::destroySurfaces(Surfaces& surfaces) const
{
if (surfaces.size() != 0) {
EXPECT_STATUS(vaDestroySurfaces(m_vaDisplay, surfaces.data(),
surfaces.size()));
}
}
void VAAPIFixture::createBuffer(const VABufferType& bufferType,
const size_t bufferSize, const VAStatus& expectation)
{
ASSERT_INVALID_ID(m_bufferID)
<< "test logic error: did you forget to call destroyBuffer?";
EXPECT_STATUS_EQ(
expectation,
vaCreateBuffer(m_vaDisplay, m_contextID, bufferType, bufferSize,
1, NULL, &m_bufferID));
}
void VAAPIFixture::destroyBuffer(const VAStatus& expectation)
{
EXPECT_STATUS_EQ(expectation, vaDestroyBuffer(m_vaDisplay, m_bufferID));
m_bufferID = VA_INVALID_ID;
}
void VAAPIFixture::doCreateContext(const Resolution& resolution,
const VAStatus& expectation)
{
m_contextID = 0;
ASSERT_STATUS_EQ(expectation,
vaCreateContext(m_vaDisplay, m_configID, resolution.width,
resolution.height, VA_PROGRESSIVE,
NULL, 0, &m_contextID));
}
void VAAPIFixture::doDestroyContext(const VAStatus& expectation)
{
ASSERT_STATUS_EQ(expectation, vaDestroyContext(m_vaDisplay, m_contextID));
}
void VAAPIFixture::doTerminate()
{
EXPECT_STATUS(vaTerminate(m_vaDisplay));
}
void VAAPIFixture::skipTest(const std::string& message)
{
ASSERT_FALSE(message.empty())
<< "test logic error: skip message cannot be empty";
ASSERT_TRUE(m_skip.empty())
<< "test logic error: test already marked as skipped";
m_skip = message;
}
void VAAPIFixture::skipTest(const VAProfile& profile,
const VAEntrypoint& entrypoint)
{
std::ostringstream oss;
oss << profile << " / " << entrypoint << " not supported on this hardware";
skipTest(oss.str());
}
TEST_F(VAAPIFixture, getDisplay)
{
VADisplay vaDisplay;
vaDisplay = getDisplay();
ASSERT_TRUE(vaDisplay);
EXPECT_STATUS(vaTerminate(vaDisplay));
}
} // namespace VAAPI