зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1787182 [Linux] Run VA-API tests on supported hardware only r=emilio,gfx-reviewers,jgilbert
- Implement fire_vaapi_process() which launch VA-API test utility on given DRM device. - Implement GfxInfo::GetDataVAAPI() which gets VA-API test results - Run VA-API tests when FEATURE_HARDWARE_VIDEO_DECODING is probed and only if it's enabled by GfxInfo. Differential Revision: https://phabricator.services.mozilla.com/D171995
This commit is contained in:
Родитель
9e0c094c88
Коммит
9a6e65770c
|
@ -15,10 +15,15 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/wait.h>
|
||||
#include <glib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/SSE.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/XREAppData.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/GUniquePtr.h"
|
||||
#include "nsCRTGlue.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
@ -29,9 +34,13 @@
|
|||
#include "prenv.h"
|
||||
#include "WidgetUtilsGtk.h"
|
||||
#include "MediaCodecsSupport.h"
|
||||
#include "nsAppRunner.h"
|
||||
|
||||
// How long we wait for data from glxtest process in milliseconds.
|
||||
#define GLXTEST_TIMEOUT 4000
|
||||
// How long we wait for data from glxtest/vaapi test process in milliseconds.
|
||||
#define GFX_TEST_TIMEOUT 4000
|
||||
#define VAAPI_TEST_TIMEOUT 2000
|
||||
|
||||
#define VAAPI_PROBE_BINARY "vaapitest"
|
||||
|
||||
#define EXIT_STATUS_BUFFER_TOO_SMALL 2
|
||||
#ifdef DEBUG
|
||||
|
@ -45,7 +54,7 @@ NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
|
|||
#endif
|
||||
|
||||
// these global variables will be set when firing the glxtest process
|
||||
int glxtest_pipe = -1;
|
||||
int glxtest_pipe = -2;
|
||||
pid_t glxtest_pid = 0;
|
||||
|
||||
// bits to use decoding codec information returned from glxtest
|
||||
|
@ -64,7 +73,6 @@ nsresult GfxInfo::Init() {
|
|||
mIsXWayland = false;
|
||||
mHasMultipleGPUs = false;
|
||||
mGlxTestError = false;
|
||||
mIsVAAPISupported = false;
|
||||
return GfxInfoBase::Init();
|
||||
}
|
||||
|
||||
|
@ -108,7 +116,7 @@ void GfxInfo::GetData() {
|
|||
}
|
||||
|
||||
const TimeStamp deadline =
|
||||
TimeStamp::Now() + TimeDuration::FromMilliseconds(GLXTEST_TIMEOUT);
|
||||
TimeStamp::Now() + TimeDuration::FromMilliseconds(GFX_TEST_TIMEOUT);
|
||||
|
||||
enum { buf_size = 2048 };
|
||||
char buf[buf_size];
|
||||
|
@ -117,7 +125,7 @@ void GfxInfo::GetData() {
|
|||
struct pollfd pfd {};
|
||||
pfd.fd = glxtest_pipe;
|
||||
pfd.events = POLLIN;
|
||||
auto ret = poll(&pfd, 1, GLXTEST_TIMEOUT);
|
||||
auto ret = poll(&pfd, 1, GFX_TEST_TIMEOUT);
|
||||
if (ret <= 0) {
|
||||
gfxCriticalNote << "glxtest: failed to read data from glxtest, we may "
|
||||
"fallback to software rendering\n";
|
||||
|
@ -248,29 +256,6 @@ void GfxInfo::GetData() {
|
|||
stringToFill = pciDevices.AppendElement();
|
||||
} else if (!strcmp(line, "DRM_RENDERDEVICE")) {
|
||||
stringToFill = &drmRenderDevice;
|
||||
} else if (!strcmp(line, "VAAPI_SUPPORTED")) {
|
||||
stringToFill = &isVAAPISupported;
|
||||
} else if (!strcmp(line, "VAAPI_HWCODECS")) {
|
||||
line = NS_strtok("\n", &bufptr);
|
||||
if (!line) break;
|
||||
int codecs = 0;
|
||||
std::istringstream(line) >> codecs;
|
||||
if (codecs & CODEC_HW_H264) {
|
||||
media::MCSInfo::AddSupport(
|
||||
media::MediaCodecsSupport::H264HardwareDecode);
|
||||
}
|
||||
if (codecs & CODEC_HW_VP8) {
|
||||
media::MCSInfo::AddSupport(
|
||||
media::MediaCodecsSupport::VP8HardwareDecode);
|
||||
}
|
||||
if (codecs & CODEC_HW_VP9) {
|
||||
media::MCSInfo::AddSupport(
|
||||
media::MediaCodecsSupport::VP9HardwareDecode);
|
||||
}
|
||||
if (codecs & CODEC_HW_AV1) {
|
||||
media::MCSInfo::AddSupport(
|
||||
media::MediaCodecsSupport::AV1HardwareDecode);
|
||||
}
|
||||
} else if (!strcmp(line, "TEST_TYPE")) {
|
||||
stringToFill = &testType;
|
||||
} else if (!strcmp(line, "WARNING")) {
|
||||
|
@ -332,7 +317,6 @@ void GfxInfo::GetData() {
|
|||
}
|
||||
|
||||
mDrmRenderDevice = std::move(drmRenderDevice);
|
||||
mIsVAAPISupported = isVAAPISupported.Equals("TRUE");
|
||||
mTestType = std::move(testType);
|
||||
|
||||
// Mesa always exposes itself in the GL_VERSION string, but not always the
|
||||
|
@ -571,6 +555,152 @@ void GfxInfo::GetData() {
|
|||
AddCrashReportAnnotations();
|
||||
}
|
||||
|
||||
int fire_vaapi_process(const char* aRenderDevicePath, int* aOutPipe) {
|
||||
nsAutoCString vaapiTestBinary;
|
||||
if (!gAppData->xreDirectory) {
|
||||
return 0;
|
||||
}
|
||||
gAppData->xreDirectory->GetNativePath(vaapiTestBinary);
|
||||
vaapiTestBinary.Append("/");
|
||||
vaapiTestBinary.Append(VAAPI_PROBE_BINARY);
|
||||
|
||||
char* argv[] = {strdup(PromiseFlatCString(vaapiTestBinary).get()),
|
||||
strdup("-d"), strdup(aRenderDevicePath), nullptr};
|
||||
auto freeArgv = mozilla::MakeScopeExit([&] {
|
||||
for (auto& arg : argv) {
|
||||
free(arg);
|
||||
}
|
||||
});
|
||||
|
||||
int pid;
|
||||
GUniquePtr<GError> err;
|
||||
g_spawn_async_with_pipes(
|
||||
nullptr, argv, nullptr,
|
||||
GSpawnFlags(G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD), nullptr,
|
||||
nullptr, &pid, nullptr, aOutPipe, nullptr, getter_Transfers(err));
|
||||
if (err) {
|
||||
gfxCriticalNote << "Failed to probe VA-API hardware! " << err->message
|
||||
<< "\n";
|
||||
pid = 0;
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
static bool MakeFdNonBlocking(int fd) {
|
||||
return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) != -1;
|
||||
}
|
||||
|
||||
void GfxInfo::GetDataVAAPI() {
|
||||
if (mIsVAAPISupported.isSome()) {
|
||||
return;
|
||||
}
|
||||
mIsVAAPISupported = Some(false);
|
||||
|
||||
int vaapiPipe = -1;
|
||||
int vaapiPID = 0;
|
||||
gsize vaapiDataLen;
|
||||
char* vaapiData = nullptr;
|
||||
GIOChannel* channel = nullptr;
|
||||
|
||||
auto free = mozilla::MakeScopeExit([&] {
|
||||
if (channel) {
|
||||
g_io_channel_unref(channel);
|
||||
}
|
||||
if (vaapiPipe >= 0) {
|
||||
close(vaapiPipe);
|
||||
}
|
||||
if (vaapiData) {
|
||||
g_free((void*)vaapiData);
|
||||
}
|
||||
if (vaapiPID) {
|
||||
int status;
|
||||
waitpid(vaapiPID, &status, WNOHANG);
|
||||
}
|
||||
});
|
||||
|
||||
vaapiPID = fire_vaapi_process(mDrmRenderDevice.get(), &vaapiPipe);
|
||||
if (!vaapiPID) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct pollfd pfd {};
|
||||
pfd.fd = vaapiPipe;
|
||||
pfd.events = POLLIN;
|
||||
auto ret = poll(&pfd, 1, VAAPI_TEST_TIMEOUT);
|
||||
if (ret <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
channel = g_io_channel_unix_new(vaapiPipe);
|
||||
MakeFdNonBlocking(vaapiPID);
|
||||
|
||||
GUniquePtr<GError> error;
|
||||
do {
|
||||
error = nullptr;
|
||||
ret = g_io_channel_read_to_end(channel, &vaapiData, &vaapiDataLen,
|
||||
getter_Transfers(error));
|
||||
} while (ret == G_IO_STATUS_AGAIN);
|
||||
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
int vaapi_exit_code = EXIT_FAILURE;
|
||||
int vaapi_status = 0;
|
||||
if (waitpid(vaapiPID, &vaapi_status, WNOHANG) < 0) {
|
||||
vaapiPID = 0;
|
||||
return;
|
||||
}
|
||||
vaapi_exit_code = WEXITSTATUS(vaapi_status);
|
||||
if (vaapi_exit_code != EXIT_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
char* bufptr = vaapiData;
|
||||
char* line;
|
||||
while ((line = NS_strtok("\n", &bufptr))) {
|
||||
if (!strcmp(line, "VAAPI_SUPPORTED")) {
|
||||
line = NS_strtok("\n", &bufptr);
|
||||
if (!line) {
|
||||
gfxCriticalNote << "vaapitest: Failed to get VAAPI support\n";
|
||||
return;
|
||||
}
|
||||
mIsVAAPISupported = Some(!strcmp(line, "TRUE"));
|
||||
} else if (!strcmp(line, "VAAPI_HWCODECS")) {
|
||||
line = NS_strtok("\n", &bufptr);
|
||||
if (!line) {
|
||||
gfxCriticalNote << "vaapitest: Failed to get VAAPI codecs\n";
|
||||
return;
|
||||
}
|
||||
int codecs = 0;
|
||||
std::istringstream(line) >> codecs;
|
||||
if (codecs & CODEC_HW_H264) {
|
||||
media::MCSInfo::AddSupport(
|
||||
media::MediaCodecsSupport::H264HardwareDecode);
|
||||
}
|
||||
if (codecs & CODEC_HW_VP8) {
|
||||
media::MCSInfo::AddSupport(
|
||||
media::MediaCodecsSupport::VP8HardwareDecode);
|
||||
}
|
||||
if (codecs & CODEC_HW_VP9) {
|
||||
media::MCSInfo::AddSupport(
|
||||
media::MediaCodecsSupport::VP9HardwareDecode);
|
||||
}
|
||||
if (codecs & CODEC_HW_AV1) {
|
||||
media::MCSInfo::AddSupport(
|
||||
media::MediaCodecsSupport::AV1HardwareDecode);
|
||||
}
|
||||
} else if (!strcmp(line, "WARNING") || !strcmp(line, "ERROR")) {
|
||||
gfxCriticalNote << "vaapitest: " << line;
|
||||
line = NS_strtok("\n", &bufptr);
|
||||
if (line) {
|
||||
gfxCriticalNote << "vaapitest: " << line << "\n";
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
|
||||
if (!sDriverInfo->Length()) {
|
||||
// Mesa 10.0 provides the GLX_MESA_query_renderer extension, which allows us
|
||||
|
@ -991,15 +1121,20 @@ nsresult GfxInfo::GetFeatureStatusImpl(
|
|||
}
|
||||
}
|
||||
|
||||
auto ret = GfxInfoBase::GetFeatureStatusImpl(
|
||||
aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
|
||||
|
||||
// Probe VA-API on supported devices only
|
||||
if (aFeature == nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING &&
|
||||
!mIsVAAPISupported) {
|
||||
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_PLATFORM_TEST;
|
||||
aFailureId = "FEATURE_FAILURE_VIDEO_DECODING_TEST_FAILED";
|
||||
return NS_OK;
|
||||
*aStatus == nsIGfxInfo::FEATURE_STATUS_OK) {
|
||||
GetDataVAAPI();
|
||||
if (!mIsVAAPISupported.value()) {
|
||||
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_PLATFORM_TEST;
|
||||
aFailureId = "FEATURE_FAILURE_VIDEO_DECODING_TEST_FAILED";
|
||||
}
|
||||
}
|
||||
|
||||
return GfxInfoBase::GetFeatureStatusImpl(
|
||||
aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
|
||||
return ret;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -112,8 +112,9 @@ class GfxInfo final : public GfxInfoBase {
|
|||
bool mIsXWayland;
|
||||
bool mHasMultipleGPUs;
|
||||
bool mGlxTestError;
|
||||
bool mIsVAAPISupported;
|
||||
mozilla::Maybe<bool> mIsVAAPISupported;
|
||||
|
||||
void GetDataVAAPI();
|
||||
void AddCrashReportAnnotations();
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче