Bug 1756459 - Record VA-API accelerated decode support in glxtest for display in about:support. r=stransky,aosmond
authoraz <azebrowski@mozilla.com>
Mon, 05 Dec 2022 09:52:59 +0000
changeset 644664 422e6572f90eab86e04210f071474afdee8754f8
parent 644663 a57a28264a06279bef1002838a5785cdd5ae274f
child 644665 a4fa2fb3beee8bd0ae5e27aecec6f39ef4b51762
push id40454
push usersmolnar@mozilla.com
push dateMon, 05 Dec 2022 16:17:17 +0000
treeherdermozilla-central@c1a849c20687 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersstransky, aosmond
bugs1756459
milestone109.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1756459 - Record VA-API accelerated decode support in glxtest for display in about:support. r=stransky,aosmond Differential Revision: https://phabricator.services.mozilla.com/D156712
toolkit/content/aboutSupport.js
toolkit/xre/glxtest.cpp
widget/gtk/GfxInfo.cpp
--- a/toolkit/content/aboutSupport.js
+++ b/toolkit/content/aboutSupport.js
@@ -1095,18 +1095,17 @@ var snapshotFormatters = {
 
     // Input devices information
     insertDeviceInfo("input", data.audioInputDevices);
 
     // Media Capabilitites
     insertEnumerateDatabase();
 
     // Codec decode/encode support information (inc. HW accel)
-    // Currently supported on Windows with Linux/OS X support under development
-    if (AppConstants.platform == "win" || AppConstants.platform == "macosx") {
+    if (["win", "macosx", "linux"].includes(AppConstants.platform)) {
       insertBasicInfo("media-codec-support-info", data.codecSupportInfo);
     }
   },
 
   remoteAgent(data) {
     if (!AppConstants.ENABLE_WEBDRIVER) {
       return;
     }
--- a/toolkit/xre/glxtest.cpp
+++ b/toolkit/xre/glxtest.cpp
@@ -172,16 +172,22 @@ namespace mozilla {
 namespace widget {
 // the read end of the pipe, which will be used by GfxInfo
 extern int glxtest_pipe;
 // the PID of the glxtest process, to pass to waitpid()
 extern pid_t glxtest_pid;
 }  // namespace widget
 }  // namespace mozilla
 
+// bits to use decoding childvaapitest() return values.
+constexpr int CODEC_HW_H264 = 1 << 4;
+constexpr int CODEC_HW_VP8 = 1 << 5;
+constexpr int CODEC_HW_VP9 = 1 << 6;
+constexpr int CODEC_HW_AV1 = 1 << 7;
+
 // the write end of the pipe, which we're going to write to
 static int write_end_of_the_pipe = -1;
 
 // our buffer, size and used length
 static char* glxtest_buf = nullptr;
 static int glxtest_bufsize = 0;
 static int glxtest_length = 0;
 
@@ -1050,16 +1056,18 @@ int childvaapitest() {
   int numProfiles = 0;
   status = vaQueryConfigProfiles(display, profiles, &numProfiles);
   if (status != VA_STATUS_SUCCESS) {
     return 9;
   }
   numProfiles = std::min(numProfiles, maxProfiles);
 
   entryPoints = new VAEntrypoint[maxEntryPoints];
+  int codecs = 0;
+  bool foundProfile = false;
   for (int p = 0; p < numProfiles; p++) {
     VAProfile profile = profiles[p];
 
     // Check only supported profiles
     if (!VAProfileName(profile)) {
       continue;
     }
 
@@ -1074,21 +1082,39 @@ int childvaapitest() {
     for (int entry = 0; entry < numEntryPoints; entry++) {
       if (entryPoints[entry] != VAEntrypointVLD) {
         continue;
       }
       VAConfigID config = VA_INVALID_ID;
       status = vaCreateConfig(display, profile, entryPoints[entry], nullptr, 0,
                               &config);
       if (status == VA_STATUS_SUCCESS) {
+        const char* profstr = VAProfileName(profile);
+        // VAProfileName returns null on failure, making the below calls safe
+        if (!strncmp(profstr, "H264", 4)) {
+          codecs |= CODEC_HW_H264;
+        } else if (!strncmp(profstr, "VP8", 3)) {
+          codecs |= CODEC_HW_VP8;
+        } else if (!strncmp(profstr, "VP9", 3)) {
+          codecs |= CODEC_HW_VP9;
+        } else if (!strncmp(profstr, "AV1", 3)) {
+          codecs |= CODEC_HW_AV1;
+        } else {
+          char warnbuf[128];
+          SprintfBuf(warnbuf, 128, "VA-API test unknown profile: %s", profstr);
+          record_warning(warnbuf);
+        }
         vaDestroyConfig(display, config);
-        return 0;
+        foundProfile = true;
       }
     }
   }
+  if (foundProfile) {
+    return codecs;
+  }
   return 10;
 }
 
 static void vaapitest() {
   if (!glxtest_render_device_path) {
     return;
   }
 
@@ -1111,19 +1137,29 @@ static void vaapitest() {
         record_warning(
             "VA-API test failed: waiting for VA-API process failed.");
       } else if (WIFEXITED(vaapitest_status) || WIFSIGNALED(vaapitest_status)) {
         wait_for_vaapitest_process = false;
       }
     }
 
     if (WIFEXITED(vaapitest_status)) {
-      switch (WEXITSTATUS(vaapitest_status)) {
+      // Note that WEXITSTATUS only returns least significant 8 bits
+      // of the exit code, despite returning type int.
+      int exitcode = WEXITSTATUS(vaapitest_status);
+      int codecs = exitcode & 0b1111'0000;
+      exitcode &= 0b0000'1111;
+      switch (exitcode) {
         case 0:
+          char codecstr[80];
           record_value("VAAPI_SUPPORTED\nTRUE\n");
+          SprintfBuf(codecstr, 80, "%d", codecs);
+          record_value("VAAPI_HWCODECS\n");
+          record_value(codecstr);
+          record_value("\n");
           break;
         case 3:
           record_warning(
               "VA-API test failed: opening render device path failed.");
           break;
         case 4:
           record_warning(
               "VA-API test failed: missing or old libva-drm library.");
--- a/widget/gtk/GfxInfo.cpp
+++ b/widget/gtk/GfxInfo.cpp
@@ -20,32 +20,39 @@
 #include "mozilla/Telemetry.h"
 #include "nsCRTGlue.h"
 #include "nsExceptionHandler.h"
 #include "nsPrintfCString.h"
 #include "nsUnicharUtils.h"
 #include "nsWhitespaceTokenizer.h"
 #include "prenv.h"
 #include "WidgetUtilsGtk.h"
+#include "MediaCodecsSupport.h"
 
 #define EXIT_STATUS_BUFFER_TOO_SMALL 2
 #ifdef DEBUG
 bool fire_glxtest_process();
 #endif
 
 namespace mozilla::widget {
 
 #ifdef DEBUG
 NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
 #endif
 
 // these global variables will be set when firing the glxtest process
 int glxtest_pipe = -1;
 pid_t glxtest_pid = 0;
 
+// bits to use decoding codec information returned from glxtest
+constexpr int CODEC_HW_H264 = 1 << 4;
+constexpr int CODEC_HW_VP8 = 1 << 5;
+constexpr int CODEC_HW_VP9 = 1 << 6;
+constexpr int CODEC_HW_AV1 = 1 << 7;
+
 nsresult GfxInfo::Init() {
   mGLMajorVersion = 0;
   mGLMinorVersion = 0;
   mHasTextureFromPixmap = false;
   mIsMesa = false;
   mIsAccelerated = true;
   mIsWayland = false;
   mIsXWayland = false;
@@ -206,16 +213,37 @@ void GfxInfo::GetData() {
     } else if (!strcmp(line, "PCI_VENDOR_ID")) {
       stringToFill = pciVendors.AppendElement();
     } else if (!strcmp(line, "PCI_DEVICE_ID")) {
       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")) {
       logString = true;
     } else if (!strcmp(line, "ERROR")) {
       logString = true;
       errorLog = true;
     }