Commit f98405be authored by Iulian Moraru's avatar Iulian Moraru
Browse files

Backed out 4 changesets (bug 1787182) for causing multiple failures. CLOSED TREE

Backed out changeset 8e5214ecc91d (bug 1787182)
Backed out changeset 41e45dcc215a (bug 1787182)
Backed out changeset 63710cc6fda4 (bug 1787182)
Backed out changeset e75ee46f3a6f (bug 1787182)
parent 80a760bb
Loading
Loading
Loading
Loading
+258 −7
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@
#include "mozilla/Unused.h"
#include "nsAppRunner.h"  // for IsWaylandEnabled on IsX11EGLEnabled
#include "stdint.h"
#include "nsExceptionHandler.h"

#ifdef __SUNPRO_CC
#  include <stdio.h>
@@ -46,7 +45,9 @@

#ifdef MOZ_WAYLAND
#  include "mozilla/widget/mozwayland.h"
#  include "mozilla/widget/xdg-output-unstable-v1-client-protocol.h"
#  include "prlink.h"
#  include "va/va.h"
#endif

#ifdef MOZ_X11
@@ -176,6 +177,17 @@ extern pid_t glxtest_pid;
}  // namespace widget
}  // namespace mozilla

#ifdef MOZ_WAYLAND
// 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;

#  define NVIDIA_VENDOR_STRING "NVIDIA Corporation"
static bool run_vaapi_test = false;
#endif

// the write end of the pipe, which we're going to write to
static int write_end_of_the_pipe = -1;

@@ -606,6 +618,13 @@ static bool get_egl_gl_status(EGLDisplay dpy,
    return false;
  }

#ifdef MOZ_WAYLAND
  // Enable VA-API testing on EGL/non-NVIDIA setup (Bug 1799747).
  if (!strstr((const char*)vendorString, NVIDIA_VENDOR_STRING)) {
    run_vaapi_test = true;
  }
#endif

  EGLDeviceEXT device;
  if (eglQueryDisplayAttribEXT(dpy, EGL_DEVICE_EXT, (EGLAttrib*)&device) ==
      EGL_TRUE) {
@@ -968,6 +987,238 @@ static void wayland_egltest() {
  wl_display_disconnect(dpy);
  record_value("TEST_TYPE\nEGL\n");
}

static constexpr struct {
  VAProfile mVAProfile;
  nsLiteralCString mName;
} kVAAPiProfileName[] = {
#  define MAP(v) \
    { VAProfile##v, nsLiteralCString(#v) }
    MAP(H264ConstrainedBaseline),
    MAP(H264Main),
    MAP(H264High),
    MAP(VP8Version0_3),
    MAP(VP9Profile0),
    MAP(VP9Profile2),
    MAP(AV1Profile0),
    MAP(AV1Profile1),
#  undef MAP
};

static const char* VAProfileName(VAProfile aVAProfile) {
  for (const auto& profile : kVAAPiProfileName) {
    if (profile.mVAProfile == aVAProfile) {
      return profile.mName.get();
    }
  }
  return nullptr;
}

int childvaapitest() {
  int renderDeviceFD = -1;
  VAProfile* profiles = nullptr;
  VAEntrypoint* entryPoints = nullptr;
  PRLibrary* libDrm = nullptr;
  VADisplay display = nullptr;

  auto autoRelease = mozilla::MakeScopeExit([&] {
    if (renderDeviceFD > -1) {
      close(renderDeviceFD);
    }
    delete[] profiles;
    delete[] entryPoints;
    if (display) {
      vaTerminate(display);
    }
    if (libDrm) {
      PR_UnloadLibrary(libDrm);
    }
  });

  renderDeviceFD = open(glxtest_render_device_path, O_RDWR);
  if (renderDeviceFD == -1) {
    return 3;
  }

  PRLibSpec lspec;
  lspec.type = PR_LibSpec_Pathname;
  const char* libName = "libva-drm.so.2";
  lspec.value.pathname = libName;
  libDrm = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
  if (!libDrm) {
    return 4;
  }

  static auto sVaGetDisplayDRM =
      (void* (*)(int fd))PR_FindSymbol(libDrm, "vaGetDisplayDRM");
  if (!sVaGetDisplayDRM) {
    return 5;
  }

  display = sVaGetDisplayDRM(renderDeviceFD);
  if (!display) {
    return 6;
  }

  int major, minor;
  VAStatus status = vaInitialize(display, &major, &minor);
  if (status != VA_STATUS_SUCCESS) {
    return 7;
  }

  int maxProfiles = vaMaxNumProfiles(display);
  int maxEntryPoints = vaMaxNumEntrypoints(display);
  if (MOZ_UNLIKELY(maxProfiles <= 0 || maxEntryPoints <= 0)) {
    return 8;
  }

  profiles = new VAProfile[maxProfiles];
  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;
    }

    int numEntryPoints = 0;
    status = vaQueryConfigEntrypoints(display, profile, entryPoints,
                                      &numEntryPoints);
    if (status != VA_STATUS_SUCCESS) {
      continue;
    }
    numEntryPoints = std::min(numEntryPoints, maxEntryPoints);

    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);
        foundProfile = true;
      }
    }
  }
  if (foundProfile) {
    return codecs;
  }
  return 10;
}

static void vaapitest() {
  if (!glxtest_render_device_path) {
    return;
  }

  pid_t vaapitest_pid = fork();
  if (vaapitest_pid == 0) {
#  if defined(MOZ_ASAN) || defined(FUZZING)
    // If handle_segv=1 (default), then glxtest crash will print a sanitizer
    // report which can confuse the harness in fuzzing automation.
    signal(SIGSEGV, SIG_DFL);
#  endif
    int vaapirv = childvaapitest();
    _exit(vaapirv);
  } else if (vaapitest_pid > 0) {
    int vaapitest_status = 0;
    bool wait_for_vaapitest_process = true;

    while (wait_for_vaapitest_process) {
      if (waitpid(vaapitest_pid, &vaapitest_status, 0) == -1) {
        wait_for_vaapitest_process = false;
        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)) {
      // 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.");
          break;
        case 5:
          record_warning("VA-API test failed: missing vaGetDisplayDRM.");
          break;
        case 6:
          record_warning("VA-API test failed: failed to get vaGetDisplayDRM.");
          break;
        case 7:
          record_warning(
              "VA-API test failed: failed to initialise VAAPI connection.");
          break;
        case 8:
          record_warning(
              "VA-API test failed: wrong VAAPI profiles/entry point nums.");
          break;
        case 9:
          record_warning("VA-API test failed: vaQueryConfigProfiles() failed.");
          break;
        case 10:
          record_warning(
              "VA-API test failed: no supported VAAPI profile found.");
          break;
        default:
          record_warning(
              "VA-API test failed: Something unexpected went wrong.");
          break;
      }
    } else {
      record_warning(
          "VA-API test failed: process crashed. Please check your VA-API "
          "drivers.");
    }
  } else {
    record_warning("VA-API test failed: Could not fork process.");
  }
}
#endif

int childgltest() {
@@ -996,6 +1247,12 @@ int childgltest() {
#endif
  }

#ifdef MOZ_WAYLAND
  if (run_vaapi_test) {
    vaapitest();
  }
#endif

  // Finally write buffered data to the pipe.
  record_flush();

@@ -1029,12 +1286,6 @@ bool fire_glxtest_process() {
    close(pfd[0]);
    write_end_of_the_pipe = pfd[1];
    close_logging();
    // This process is expected to be crashy, and we
    // don't want the user to see its crashes. That's the whole reason for
    // doing this in a separate process.
    if (CrashReporter::GetEnabled()) {
      CrashReporter::UnsetExceptionHandler();
    }
#if defined(MOZ_ASAN) || defined(FUZZING)
    // If handle_segv=1 (default), then glxtest crash will print a sanitizer
    // report which can confuse the harness in fuzzing automation.
+8 −0
Original line number Diff line number Diff line
@@ -158,6 +158,14 @@ if CONFIG["MOZ_X11"] or CONFIG["MOZ_WAYLAND"]:
        "glxtest.cpp",
    ]

if CONFIG["MOZ_WAYLAND"]:
    LOCAL_INCLUDES += [
        "/media/mozva",
    ]
    USE_LIBS += [
        "mozva",
    ]

if CONFIG["MOZ_INSTRUMENT_EVENT_LOOP"]:
    UNIFIED_SOURCES += [
        "EventTracer.cpp",
+11 −4
Original line number Diff line number Diff line
@@ -3950,6 +3950,17 @@ int XREMain::XRE_mainInit(bool* aExitFlag) {

  mozilla::startup::IncreaseDescriptorLimits();

#ifdef USE_GLX_TEST
  // bug 639842 - it's very important to fire this process BEFORE we set up
  // error handling. indeed, this process is expected to be crashy, and we
  // don't want the user to see its crashes. That's the whole reason for
  // doing this in a separate process.
  //
  // This call will cause a fork and the fork will terminate itself separately
  // from the usual shutdown sequence
  fire_glxtest_process();
#endif

  SetupErrorHandling(gArgv[0]);

#ifdef CAIRO_HAS_DWRITE_FONT
@@ -5111,10 +5122,6 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
  // Flush any pending page load events.
  mozilla::glean_pings::Pageload.Submit("startup"_ns);

#ifdef USE_GLX_TEST
  fire_glxtest_process();
#endif

  return 0;
}

+36 −167
Original line number Diff line number Diff line
@@ -29,14 +29,9 @@
#include "prenv.h"
#include "WidgetUtilsGtk.h"
#include "MediaCodecsSupport.h"
#include "nsAppRunner.h"
#include "mozilla/XREAppData.h"

// 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"
// How long we wait for data from glxtest process in milliseconds.
#define GLXTEST_TIMEOUT 4000

#define EXIT_STATUS_BUFFER_TOO_SMALL 2
#ifdef DEBUG
@@ -50,7 +45,7 @@ NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
#endif

// these global variables will be set when firing the glxtest process
int glxtest_pipe = -2;
int glxtest_pipe = -1;
pid_t glxtest_pid = 0;

// bits to use decoding codec information returned from glxtest
@@ -69,6 +64,7 @@ nsresult GfxInfo::Init() {
  mIsXWayland = false;
  mHasMultipleGPUs = false;
  mGlxTestError = false;
  mIsVAAPISupported = false;
  return GfxInfoBase::Init();
}

@@ -112,7 +108,7 @@ void GfxInfo::GetData() {
  }

  const TimeStamp deadline =
      TimeStamp::Now() + TimeDuration::FromMilliseconds(GFX_TEST_TIMEOUT);
      TimeStamp::Now() + TimeDuration::FromMilliseconds(GLXTEST_TIMEOUT);

  enum { buf_size = 2048 };
  char buf[buf_size];
@@ -121,7 +117,7 @@ void GfxInfo::GetData() {
  struct pollfd pfd {};
  pfd.fd = glxtest_pipe;
  pfd.events = POLLIN;
  auto ret = poll(&pfd, 1, GFX_TEST_TIMEOUT);
  auto ret = poll(&pfd, 1, GLXTEST_TIMEOUT);
  if (ret <= 0) {
    gfxCriticalNote << "glxtest: failed to read data from glxtest, we may "
                       "fallback to software rendering\n";
@@ -252,6 +248,29 @@ 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")) {
@@ -313,6 +332,7 @@ 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
@@ -551,152 +571,6 @@ 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
@@ -1110,20 +984,15 @@ 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 &&
      *aStatus == nsIGfxInfo::FEATURE_STATUS_OK) {
    GetDataVAAPI();
    if (!mIsVAAPISupported.value()) {
      !mIsVAAPISupported) {
    *aStatus = nsIGfxInfo::FEATURE_BLOCKED_PLATFORM_TEST;
    aFailureId = "FEATURE_FAILURE_VIDEO_DECODING_TEST_FAILED";
    }
    return NS_OK;
  }

  return ret;
  return GfxInfoBase::GetFeatureStatusImpl(
      aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aFailureId, &os);
}

NS_IMETHODIMP
+1 −2
Original line number Diff line number Diff line
@@ -112,9 +112,8 @@ class GfxInfo final : public GfxInfoBase {
  bool mIsXWayland;
  bool mHasMultipleGPUs;
  bool mGlxTestError;
  mozilla::Maybe<bool> mIsVAAPISupported;
  bool mIsVAAPISupported;

  void GetDataVAAPI();
  void AddCrashReportAnnotations();
};

Loading