зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1787182 [Linux] Implement glxtest test as binary r=emilio
glxtest is run later when Firefox already spawns threads. Recently glxtest runs in forked process which doesn't work correctly in multi-thread environment, so we need to move glxtest to different binary file and launch it as stand alone code. Differential Revision: https://phabricator.services.mozilla.com/D173486
This commit is contained in:
Родитель
aa36e08377
Коммит
21ea86344c
|
@ -160,6 +160,7 @@
|
|||
#endif
|
||||
#ifdef MOZ_GTK
|
||||
@BINPATH@/vaapitest
|
||||
@BINPATH@/glxtest
|
||||
#endif
|
||||
|
||||
; [Components]
|
||||
|
|
|
@ -24,16 +24,16 @@
|
|||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if defined(MOZ_ASAN) || defined(FUZZING)
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsAppRunner.h" // for IsWaylandEnabled on IsX11EGLEnabled
|
||||
#include "stdint.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
|
||||
#ifdef __SUNPRO_CC
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
@ -44,16 +44,9 @@
|
|||
# include <X11/extensions/Xrandr.h>
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WAYLAND
|
||||
# include "mozilla/widget/mozwayland.h"
|
||||
# include "prlink.h"
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <sys/wait.h>
|
||||
#include "nsString.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
|
||||
#ifdef MOZ_X11
|
||||
// stuff from glx.h
|
||||
|
@ -173,6 +166,19 @@ typedef struct _drmDevice {
|
|||
|
||||
#define EXIT_FAILURE_BUFFER_TOO_SMALL 2
|
||||
|
||||
// An alternative to mozilla::Unused for use in (a) C code and (b) code where
|
||||
// linking with unused.o is difficult.
|
||||
#define MOZ_UNUSED(expr) \
|
||||
do { \
|
||||
if (expr) { \
|
||||
(void)0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Print VA-API test results to stdout and logging to stderr
|
||||
#define OUTPUT_PIPE 1
|
||||
#define LOG_PIPE 2
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
// the read end of the pipe, which will be used by GfxInfo
|
||||
|
@ -182,16 +188,11 @@ extern pid_t glxtest_pid;
|
|||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
// 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;
|
||||
|
||||
static char* glxtest_render_device_path = nullptr;
|
||||
|
||||
// C++ standard collides with C standard in that it doesn't allow casting void*
|
||||
// to function pointer types. So the work-around is to convert first to size_t.
|
||||
// http://www.trilithium.com/johan/2004/12/problem-with-dlsym/
|
||||
|
@ -231,14 +232,9 @@ static void record_warning(const char* str) {
|
|||
}
|
||||
|
||||
static void record_flush() {
|
||||
mozilla::Unused << write(write_end_of_the_pipe, glxtest_buf, glxtest_length);
|
||||
if (auto* debugFile = getenv("MOZ_GFX_DEBUG_FILE")) {
|
||||
auto fd = open(debugFile, O_CREAT | O_WRONLY | O_TRUNC,
|
||||
S_IRUSR | S_IRGRP | S_IROTH);
|
||||
if (fd != -1) {
|
||||
mozilla::Unused << write(fd, glxtest_buf, glxtest_length);
|
||||
close(fd);
|
||||
}
|
||||
MOZ_UNUSED(write(OUTPUT_PIPE, glxtest_buf, glxtest_length));
|
||||
if (getenv("MOZ_GFX_DEBUG")) {
|
||||
MOZ_UNUSED(write(LOG_PIPE, glxtest_buf, glxtest_length));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,24 +255,6 @@ static int x_error_handler(Display*, XErrorEvent* ev) {
|
|||
// care about leaking memory
|
||||
extern "C" {
|
||||
|
||||
static void close_logging() {
|
||||
// we want to redirect to /dev/null stdout, stderr, and while we're at it,
|
||||
// any PR logging file descriptors. To that effect, we redirect all positive
|
||||
// file descriptors up to what open() returns here. In particular, 1 is stdout
|
||||
// and 2 is stderr.
|
||||
int fd = open("/dev/null", O_WRONLY);
|
||||
for (int i = 1; i < fd; i++) {
|
||||
dup2(fd, i);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
if (getenv("MOZ_AVOID_OPENGL_ALTOGETHER")) {
|
||||
const char* msg = "ERROR\nMOZ_AVOID_OPENGL_ALTOGETHER envvar set";
|
||||
mozilla::Unused << write(write_end_of_the_pipe, msg, strlen(msg));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
#define PCI_FILL_IDENT 0x0001
|
||||
#define PCI_FILL_CLASS 0x0020
|
||||
#define PCI_BASE_CLASS_DISPLAY 0x03
|
||||
|
@ -296,6 +274,7 @@ static void get_pci_status() {
|
|||
record_warning("libpci missing");
|
||||
return;
|
||||
}
|
||||
auto release = mozilla::MakeScopeExit([&] { dlclose(libpci); });
|
||||
|
||||
typedef struct pci_dev {
|
||||
struct pci_dev* next;
|
||||
|
@ -344,7 +323,6 @@ static void get_pci_status() {
|
|||
|
||||
pci_access* pacc = pci_alloc();
|
||||
if (!pacc) {
|
||||
dlclose(libpci);
|
||||
record_warning("libpci alloc failed");
|
||||
return;
|
||||
}
|
||||
|
@ -362,13 +340,11 @@ static void get_pci_status() {
|
|||
}
|
||||
|
||||
pci_cleanup(pacc);
|
||||
dlclose(libpci);
|
||||
}
|
||||
|
||||
#ifdef MOZ_WAYLAND
|
||||
static void set_render_device_path(const char* render_device_path) {
|
||||
record_value("DRM_RENDERDEVICE\n%s\n", render_device_path);
|
||||
glxtest_render_device_path = strdup(render_device_path);
|
||||
}
|
||||
|
||||
static bool device_has_name(const drmDevice* device, const char* name) {
|
||||
|
@ -389,6 +365,7 @@ static bool get_render_name(const char* name) {
|
|||
record_warning("Failed to open libdrm");
|
||||
return false;
|
||||
}
|
||||
auto release = mozilla::MakeScopeExit([&] { dlclose(libdrm); });
|
||||
|
||||
typedef int (*DRMGETDEVICES2)(uint32_t, drmDevicePtr*, int);
|
||||
DRMGETDEVICES2 drmGetDevices2 =
|
||||
|
@ -401,7 +378,6 @@ static bool get_render_name(const char* name) {
|
|||
if (!drmGetDevices2 || !drmFreeDevice) {
|
||||
record_warning(
|
||||
"libdrm missing methods for drmGetDevices2 or drmFreeDevice");
|
||||
dlclose(libdrm);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -409,20 +385,17 @@ static bool get_render_name(const char* name) {
|
|||
int devices_len = drmGetDevices2(flags, nullptr, 0);
|
||||
if (devices_len < 0) {
|
||||
record_warning("drmGetDevices2 failed");
|
||||
dlclose(libdrm);
|
||||
return false;
|
||||
}
|
||||
drmDevice** devices = (drmDevice**)calloc(devices_len, sizeof(drmDevice*));
|
||||
if (!devices) {
|
||||
record_warning("Allocation error");
|
||||
dlclose(libdrm);
|
||||
return false;
|
||||
}
|
||||
devices_len = drmGetDevices2(flags, devices, devices_len);
|
||||
if (devices_len < 0) {
|
||||
free(devices);
|
||||
record_warning("drmGetDevices2 failed");
|
||||
dlclose(libdrm);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -474,8 +447,6 @@ static bool get_render_name(const char* name) {
|
|||
drmFreeDevice(&devices[i]);
|
||||
}
|
||||
free(devices);
|
||||
|
||||
dlclose(libdrm);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
@ -498,6 +469,11 @@ static bool get_egl_gl_status(EGLDisplay dpy,
|
|||
PFNEGLCREATECONTEXTPROC eglCreateContext =
|
||||
cast<PFNEGLCREATECONTEXTPROC>(eglGetProcAddress("eglCreateContext"));
|
||||
|
||||
typedef EGLBoolean (*PFNEGLDESTROYCONTEXTPROC)(EGLDisplay dpy,
|
||||
EGLContext ctx);
|
||||
PFNEGLDESTROYCONTEXTPROC eglDestroyContext =
|
||||
cast<PFNEGLDESTROYCONTEXTPROC>(eglGetProcAddress("eglDestroyContext"));
|
||||
|
||||
typedef EGLBoolean (*PFNEGLMAKECURRENTPROC)(
|
||||
EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext context);
|
||||
PFNEGLMAKECURRENTPROC eglMakeCurrent =
|
||||
|
@ -515,8 +491,8 @@ static bool get_egl_gl_status(EGLDisplay dpy,
|
|||
cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>(
|
||||
eglGetProcAddress("eglQueryDisplayAttribEXT"));
|
||||
|
||||
if (!eglChooseConfig || !eglCreateContext || !eglMakeCurrent ||
|
||||
!eglQueryDeviceStringEXT) {
|
||||
if (!eglChooseConfig || !eglCreateContext || !eglDestroyContext ||
|
||||
!eglMakeCurrent || !eglQueryDeviceStringEXT) {
|
||||
record_warning("libEGL missing methods for GL test");
|
||||
return false;
|
||||
}
|
||||
|
@ -570,9 +546,11 @@ static bool get_egl_gl_status(EGLDisplay dpy,
|
|||
}
|
||||
|
||||
if (eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ectx) == EGL_FALSE) {
|
||||
eglDestroyContext(dpy, ectx);
|
||||
record_warning("eglMakeCurrent returned an error");
|
||||
return false;
|
||||
}
|
||||
eglDestroyContext(dpy, ectx);
|
||||
|
||||
// Implementations disagree about whether eglGetProcAddress or dlsym
|
||||
// should be used for getting functions from the actual API, see
|
||||
|
@ -595,6 +573,11 @@ static bool get_egl_gl_status(EGLDisplay dpy,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
auto release = mozilla::MakeScopeExit([&] {
|
||||
if (libgl) {
|
||||
dlclose(libgl);
|
||||
}
|
||||
});
|
||||
|
||||
const GLubyte* versionString = glGetString(GL_VERSION);
|
||||
const GLubyte* vendorString = glGetString(GL_VENDOR);
|
||||
|
@ -605,9 +588,6 @@ static bool get_egl_gl_status(EGLDisplay dpy,
|
|||
vendorString, rendererString, versionString);
|
||||
} else {
|
||||
record_warning("EGL glGetString returned null");
|
||||
if (libgl) {
|
||||
dlclose(libgl);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -633,25 +613,34 @@ static bool get_egl_gl_status(EGLDisplay dpy,
|
|||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (libgl) {
|
||||
dlclose(libgl);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_egl_status(EGLNativeDisplayType native_dpy) {
|
||||
EGLDisplay dpy = nullptr;
|
||||
|
||||
typedef EGLBoolean (*PFNEGLTERMINATEPROC)(EGLDisplay dpy);
|
||||
PFNEGLTERMINATEPROC eglTerminate = nullptr;
|
||||
|
||||
void* libegl = dlopen(LIBEGL_FILENAME, RTLD_LAZY);
|
||||
if (!libegl) {
|
||||
record_warning("libEGL missing");
|
||||
return false;
|
||||
}
|
||||
auto release = mozilla::MakeScopeExit([&] {
|
||||
if (dpy) {
|
||||
eglTerminate(dpy);
|
||||
}
|
||||
// Unload libegl here causes ASAN/MemLeaks failures on Linux
|
||||
// as libegl may not be meant to be unloaded runtime.
|
||||
// See 1304156 for reference.
|
||||
// dlclose(libegl);
|
||||
});
|
||||
|
||||
PFNEGLGETPROCADDRESS eglGetProcAddress =
|
||||
cast<PFNEGLGETPROCADDRESS>(dlsym(libegl, "eglGetProcAddress"));
|
||||
|
||||
if (!eglGetProcAddress) {
|
||||
dlclose(libegl);
|
||||
record_warning("no eglGetProcAddress");
|
||||
return false;
|
||||
}
|
||||
|
@ -664,27 +653,21 @@ static bool get_egl_status(EGLNativeDisplayType native_dpy) {
|
|||
EGLint * minor);
|
||||
PFNEGLINITIALIZEPROC eglInitialize =
|
||||
cast<PFNEGLINITIALIZEPROC>(eglGetProcAddress("eglInitialize"));
|
||||
|
||||
typedef EGLBoolean (*PFNEGLTERMINATEPROC)(EGLDisplay dpy);
|
||||
PFNEGLTERMINATEPROC eglTerminate =
|
||||
cast<PFNEGLTERMINATEPROC>(eglGetProcAddress("eglTerminate"));
|
||||
eglTerminate = cast<PFNEGLTERMINATEPROC>(eglGetProcAddress("eglTerminate"));
|
||||
|
||||
if (!eglGetDisplay || !eglInitialize || !eglTerminate) {
|
||||
dlclose(libegl);
|
||||
record_warning("libEGL missing methods");
|
||||
return false;
|
||||
}
|
||||
|
||||
EGLDisplay dpy = eglGetDisplay(native_dpy);
|
||||
dpy = eglGetDisplay(native_dpy);
|
||||
if (!dpy) {
|
||||
dlclose(libegl);
|
||||
record_warning("libEGL no display");
|
||||
return false;
|
||||
}
|
||||
|
||||
EGLint major, minor;
|
||||
if (!eglInitialize(dpy, &major, &minor)) {
|
||||
dlclose(libegl);
|
||||
record_warning("libEGL initialize failed");
|
||||
return false;
|
||||
}
|
||||
|
@ -700,15 +683,7 @@ static bool get_egl_status(EGLNativeDisplayType native_dpy) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!get_egl_gl_status(dpy, eglGetProcAddress)) {
|
||||
eglTerminate(dpy);
|
||||
dlclose(libegl);
|
||||
return false;
|
||||
}
|
||||
|
||||
eglTerminate(dpy);
|
||||
dlclose(libegl);
|
||||
return true;
|
||||
return get_egl_gl_status(dpy, eglGetProcAddress);
|
||||
}
|
||||
|
||||
#ifdef MOZ_X11
|
||||
|
@ -725,22 +700,49 @@ static void get_xrandr_info(Display* dpy) {
|
|||
|
||||
Window root = RootWindow(dpy, DefaultScreen(dpy));
|
||||
XRRProviderResources* pr = XRRGetProviderResources(dpy, root);
|
||||
if (!pr) {
|
||||
return;
|
||||
}
|
||||
XRRScreenResources* res = XRRGetScreenResourcesCurrent(dpy, root);
|
||||
if (!res) {
|
||||
XRRFreeProviderResources(pr);
|
||||
return;
|
||||
}
|
||||
if (pr->nproviders != 0) {
|
||||
record_value("DDX_DRIVER\n");
|
||||
for (int i = 0; i < pr->nproviders; i++) {
|
||||
XRRProviderInfo* info = XRRGetProviderInfo(dpy, res, pr->providers[i]);
|
||||
record_value("%s%s", info->name, i == pr->nproviders - 1 ? ";\n" : ";");
|
||||
if (info) {
|
||||
record_value("%s%s", info->name, i == pr->nproviders - 1 ? ";\n" : ";");
|
||||
XRRFreeProviderInfo(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
XRRFreeScreenResources(res);
|
||||
XRRFreeProviderResources(pr);
|
||||
}
|
||||
|
||||
static void glxtest() {
|
||||
void glxtest() {
|
||||
Display* dpy = nullptr;
|
||||
void* libgl = dlopen(LIBGL_FILENAME, RTLD_LAZY);
|
||||
if (!libgl) {
|
||||
record_error(LIBGL_FILENAME " missing");
|
||||
return;
|
||||
}
|
||||
auto release = mozilla::MakeScopeExit([&] {
|
||||
if (dpy) {
|
||||
# ifdef MOZ_ASAN
|
||||
XCloseDisplay(dpy);
|
||||
# else
|
||||
// This XSync call wanted to be instead:
|
||||
// XCloseDisplay(dpy);
|
||||
// but this can cause 1-minute stalls on certain setups using Nouveau, see
|
||||
// bug 973192
|
||||
XSync(dpy, False);
|
||||
# endif
|
||||
}
|
||||
dlclose(libgl);
|
||||
});
|
||||
|
||||
typedef void* (*PFNGLXGETPROCADDRESS)(const char*);
|
||||
PFNGLXGETPROCADDRESS glXGetProcAddress =
|
||||
|
@ -788,7 +790,7 @@ static void glxtest() {
|
|||
}
|
||||
|
||||
///// Open a connection to the X server /////
|
||||
Display* dpy = XOpenDisplay(nullptr);
|
||||
dpy = XOpenDisplay(nullptr);
|
||||
if (!dpy) {
|
||||
record_error("Unable to open a connection to the X server");
|
||||
return;
|
||||
|
@ -903,28 +905,24 @@ static void glxtest() {
|
|||
glXDestroyContext(dpy, context);
|
||||
XDestroyWindow(dpy, window);
|
||||
XFreeColormap(dpy, swa.colormap);
|
||||
|
||||
# ifdef NS_FREE_PERMANENT_DATA // conditionally defined in nscore.h, don't
|
||||
// forget to #include it above
|
||||
XCloseDisplay(dpy);
|
||||
# else
|
||||
// This XSync call wanted to be instead:
|
||||
// XCloseDisplay(dpy);
|
||||
// but this can cause 1-minute stalls on certain setups using Nouveau, see bug
|
||||
// 973192
|
||||
XSync(dpy, False);
|
||||
# endif
|
||||
|
||||
dlclose(libgl);
|
||||
XFree(vInfo);
|
||||
|
||||
record_value("TEST_TYPE\nGLX\n");
|
||||
}
|
||||
|
||||
static bool x11_egltest() {
|
||||
bool x11_egltest() {
|
||||
Display* dpy = XOpenDisplay(nullptr);
|
||||
if (!dpy) {
|
||||
return false;
|
||||
}
|
||||
# ifdef MOZ_ASAN
|
||||
auto release = mozilla::MakeScopeExit([&] {
|
||||
// Bug 1715245: Closing the display connection here crashes on NV prop.
|
||||
// drivers. Just leave it open, the process will exit shortly after anyway.
|
||||
XCloseDisplay(dpy);
|
||||
});
|
||||
# endif
|
||||
|
||||
XSetErrorHandler(x_error_handler);
|
||||
|
||||
if (!get_egl_status(dpy)) {
|
||||
|
@ -943,20 +941,28 @@ static bool x11_egltest() {
|
|||
// Get monitor and DDX driver information
|
||||
get_xrandr_info(dpy);
|
||||
|
||||
// Bug 1715245: Closing the display connection here crashes on NV prop.
|
||||
// drivers. Just leave it open, the process will exit shortly after anyway.
|
||||
// XCloseDisplay(dpy);
|
||||
|
||||
record_value("TEST_TYPE\nEGL\n");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WAYLAND
|
||||
static void wayland_egltest() {
|
||||
void wayland_egltest() {
|
||||
static auto sWlDisplayConnect = (struct wl_display * (*)(const char*))
|
||||
dlsym(RTLD_DEFAULT, "wl_display_connect");
|
||||
static auto sWlDisplayRoundtrip =
|
||||
(int (*)(struct wl_display*))dlsym(RTLD_DEFAULT, "wl_display_roundtrip");
|
||||
static auto sWlDisplayDisconnect = (void (*)(struct wl_display*))dlsym(
|
||||
RTLD_DEFAULT, "wl_display_disconnect");
|
||||
|
||||
if (!sWlDisplayConnect || !sWlDisplayRoundtrip || !sWlDisplayDisconnect) {
|
||||
record_error("Missing Wayland libraries");
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: returns false to fall back to X11 when the Wayland socket doesn't
|
||||
// exist but fails with record_error if something actually went wrong
|
||||
struct wl_display* dpy = wl_display_connect(nullptr);
|
||||
struct wl_display* dpy = sWlDisplayConnect(nullptr);
|
||||
if (!dpy) {
|
||||
record_error("Could not connect to wayland socket");
|
||||
return;
|
||||
|
@ -968,14 +974,14 @@ static void wayland_egltest() {
|
|||
|
||||
// This is enough to crash some broken NVIDIA prime + Wayland setups, see
|
||||
// https://github.com/NVIDIA/egl-wayland/issues/41 and bug 1768260.
|
||||
wl_display_roundtrip(dpy);
|
||||
sWlDisplayRoundtrip(dpy);
|
||||
|
||||
wl_display_disconnect(dpy);
|
||||
sWlDisplayDisconnect(dpy);
|
||||
record_value("TEST_TYPE\nEGL\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
int childgltest() {
|
||||
int childgltest(bool aWayland) {
|
||||
enum { bufsize = 2048 };
|
||||
char buf[bufsize];
|
||||
|
||||
|
@ -988,19 +994,18 @@ int childgltest() {
|
|||
get_pci_status();
|
||||
|
||||
#ifdef MOZ_WAYLAND
|
||||
if (IsWaylandEnabled()) {
|
||||
if (aWayland) {
|
||||
wayland_egltest();
|
||||
} else
|
||||
}
|
||||
#endif
|
||||
{
|
||||
#ifdef MOZ_X11
|
||||
if (!aWayland) {
|
||||
// TODO: --display command line argument is not properly handled
|
||||
if (!x11_egltest()) {
|
||||
glxtest();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
// Finally write buffered data to the pipe.
|
||||
record_flush();
|
||||
|
||||
|
@ -1014,44 +1019,48 @@ int childgltest() {
|
|||
|
||||
} // extern "C"
|
||||
|
||||
/** \returns true in the child glxtest process, false in the parent process */
|
||||
bool fire_glxtest_process() {
|
||||
int pfd[2];
|
||||
if (pipe(pfd) == -1) {
|
||||
perror("pipe");
|
||||
return false;
|
||||
}
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("fork");
|
||||
close(pfd[0]);
|
||||
close(pfd[1]);
|
||||
return false;
|
||||
}
|
||||
// The child exits early to avoid running the full shutdown sequence and avoid
|
||||
// conflicting with threads we have already spawned (like the profiler).
|
||||
if (pid == 0) {
|
||||
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.
|
||||
signal(SIGSEGV, SIG_DFL);
|
||||
#endif
|
||||
int rv = childgltest();
|
||||
close(pfd[1]);
|
||||
_exit(rv);
|
||||
}
|
||||
|
||||
close(pfd[1]);
|
||||
mozilla::widget::glxtest_pipe = pfd[0];
|
||||
mozilla::widget::glxtest_pid = pid;
|
||||
return false;
|
||||
static void PrintUsage() {
|
||||
printf(
|
||||
"Firefox OpenGL probe utility\n"
|
||||
"\n"
|
||||
"usage: glxtest [options]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
"\n"
|
||||
" -h --help show this message\n"
|
||||
" -w --wayland probe OpenGL/EGL on Wayland (default is "
|
||||
"X11)\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
struct option longOptions[] = {{"help", no_argument, NULL, 'h'},
|
||||
{"wayland", no_argument, NULL, 'w'},
|
||||
{NULL, 0, NULL, 0}};
|
||||
const char* shortOptions = "hw";
|
||||
int c;
|
||||
bool wayland = false;
|
||||
while ((c = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'w':
|
||||
wayland = true;
|
||||
break;
|
||||
case 'h':
|
||||
PrintUsage();
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (getenv("MOZ_AVOID_OPENGL_ALTOGETHER")) {
|
||||
const char* msg = "ERROR\nMOZ_AVOID_OPENGL_ALTOGETHER envvar set";
|
||||
(void)write(OUTPUT_PIPE, msg, strlen(msg));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#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
|
||||
return childgltest(wayland);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "Widget: Gtk")
|
||||
|
||||
Program("glxtest")
|
||||
SOURCES += [
|
||||
"glxtest.cpp",
|
||||
]
|
||||
|
||||
if CONFIG["MOZ_ASAN"]:
|
||||
SOURCES += [
|
||||
"../../../mozglue/build/AsanOptions.cpp",
|
||||
]
|
||||
|
||||
CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]
|
||||
CXXFLAGS += CONFIG["MOZ_PANGO_CFLAGS"]
|
||||
OS_LIBS += CONFIG["MOZ_X11_LIBS"]
|
||||
OS_LIBS += CONFIG["MOZ_GTK3_LIBS"]
|
||||
|
||||
NO_PGO = True
|
||||
DisableStlWrapping()
|
|
@ -153,11 +153,6 @@ SOURCES += [
|
|||
"ProfileReset.cpp",
|
||||
]
|
||||
|
||||
if CONFIG["MOZ_X11"] or CONFIG["MOZ_WAYLAND"]:
|
||||
UNIFIED_SOURCES += [
|
||||
"glxtest.cpp",
|
||||
]
|
||||
|
||||
if CONFIG["MOZ_INSTRUMENT_EVENT_LOOP"]:
|
||||
UNIFIED_SOURCES += [
|
||||
"EventTracer.cpp",
|
||||
|
@ -186,6 +181,7 @@ FINAL_LIBRARY = "xul"
|
|||
|
||||
if CONFIG["MOZ_X11"] or CONFIG["MOZ_WAYLAND"]:
|
||||
DEFINES["USE_GLX_TEST"] = True
|
||||
DIRS += ["glxtest"]
|
||||
|
||||
for var in (
|
||||
"MOZ_APP_NAME",
|
||||
|
|
|
@ -254,6 +254,10 @@
|
|||
# include "nsIStringBundle.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_GLX_TEST
|
||||
# include "mozilla/GUniquePtr.h"
|
||||
#endif
|
||||
|
||||
extern uint32_t gRestartMode;
|
||||
extern void InstallSignalHandlers(const char* ProgramName);
|
||||
|
||||
|
@ -321,11 +325,6 @@ nsString gProcessStartupShortcut;
|
|||
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
# include <glib.h>
|
||||
# if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING)
|
||||
# define CLEANUP_MEMORY 1
|
||||
# define PANGO_ENABLE_BACKEND
|
||||
# include <pango/pangofc-fontmap.h>
|
||||
# endif
|
||||
# include "mozilla/WidgetUtilsGtk.h"
|
||||
# include <gtk/gtk.h>
|
||||
# ifdef MOZ_WAYLAND
|
||||
|
@ -335,7 +334,6 @@ nsString gProcessStartupShortcut;
|
|||
# ifdef MOZ_X11
|
||||
# include <gdk/gdkx.h>
|
||||
# endif /* MOZ_X11 */
|
||||
# include <fontconfig/fontconfig.h>
|
||||
#endif
|
||||
#include "BinaryPath.h"
|
||||
|
||||
|
@ -3620,7 +3618,41 @@ static DWORD WINAPI InitDwriteBG(LPVOID lpdwThreadParam) {
|
|||
#endif
|
||||
|
||||
#ifdef USE_GLX_TEST
|
||||
bool fire_glxtest_process();
|
||||
namespace mozilla::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 mozilla::widget
|
||||
|
||||
void fire_glxtest_process() {
|
||||
if (!gAppData || !gAppData->xreDirectory) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString glxTestBinary;
|
||||
gAppData->xreDirectory->GetNativePath(glxTestBinary);
|
||||
glxTestBinary.Append("/");
|
||||
glxTestBinary.Append("glxtest");
|
||||
|
||||
char* argv[] = {strdup(glxTestBinary.get()),
|
||||
IsWaylandEnabled() ? strdup("-w") : nullptr, nullptr};
|
||||
auto freeArgv = mozilla::MakeScopeExit([&] {
|
||||
for (auto& arg : argv) {
|
||||
free(arg);
|
||||
}
|
||||
});
|
||||
|
||||
GUniquePtr<GError> err;
|
||||
g_spawn_async_with_pipes(
|
||||
nullptr, argv, nullptr,
|
||||
GSpawnFlags(G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD), nullptr,
|
||||
nullptr, &mozilla::widget::glxtest_pid, nullptr,
|
||||
&mozilla::widget::glxtest_pipe, nullptr, getter_Transfers(err));
|
||||
if (err) {
|
||||
Output(true, "Failed to probe graphics hardware! %s\n", err->message);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "GeckoProfiler.h"
|
||||
|
@ -4424,6 +4456,8 @@ bool IsWaylandEnabled() {
|
|||
return false;
|
||||
# endif
|
||||
}
|
||||
#else
|
||||
bool IsWaylandEnabled() { return false; }
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID)
|
||||
|
@ -4702,10 +4736,7 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
|
|||
saveDisplayArg = true;
|
||||
}
|
||||
|
||||
bool waylandEnabled = false;
|
||||
# if defined(MOZ_WAYLAND)
|
||||
waylandEnabled = IsWaylandEnabled();
|
||||
# endif
|
||||
bool waylandEnabled = IsWaylandEnabled();
|
||||
// On Wayland disabled builds read X11 DISPLAY env exclusively
|
||||
// and don't care about different displays.
|
||||
if (!waylandEnabled && !display_name) {
|
||||
|
|
|
@ -163,7 +163,7 @@ void GfxInfo::GetData() {
|
|||
wait_for_glxtest_process = true;
|
||||
} else {
|
||||
// Bug 718629
|
||||
// ECHILD happens when the glxtest process got reaped got reaped after a
|
||||
// ECHILD happens when the glxtest process got reaped after a
|
||||
// PR_CreateProcess as per bug 227246. This shouldn't matter, as we
|
||||
// still seem to get the data from the pipe, and if we didn't, the
|
||||
// outcome would be to blocklist anyway.
|
||||
|
|
Загрузка…
Ссылка в новой задаче