From c108212cf86f77df44d3a7fa92f12c9dcd592f7c Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 31 Oct 2016 23:43:40 +0100 Subject: [PATCH] If EGL initialization fails, print a friendlier error message. The libpci dependency might be a bit overkill, but it really helps friendliness in an otherwise pretty inscrutinable case. --- Makefile | 2 +- README | 4 ++- context.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++-- context.h | 1 + main.cpp | 1 + 5 files changed, 99 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 968fa63..6b79254 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CXX=g++ PROTOC=protoc INSTALL=install EMBEDDED_BMUSB=no -PKG_MODULES := Qt5Core Qt5Gui Qt5Widgets Qt5OpenGLExtensions Qt5OpenGL libusb-1.0 movit lua52 libmicrohttpd epoxy x264 protobuf +PKG_MODULES := Qt5Core Qt5Gui Qt5Widgets Qt5OpenGLExtensions Qt5OpenGL libusb-1.0 movit lua52 libmicrohttpd epoxy x264 protobuf libpci CXXFLAGS ?= -O2 -g -Wall # Will be overridden by environment. CXXFLAGS += -std=gnu++11 -fPIC $(shell pkg-config --cflags $(PKG_MODULES)) -pthread -DMOVIT_SHADER_DIR=\"$(shell pkg-config --variable=shaderdir movit)\" -Idecklink/ diff --git a/README b/README index 02f02eb..43e68c4 100644 --- a/README +++ b/README @@ -64,6 +64,8 @@ Nageru is in beta stage. It currently needs: - Lua, for driving the theme engine. + - libpci, for printing friendly PCI device names in an error message. + If on Debian stretch or something similar, you can install everything you need with: @@ -72,7 +74,7 @@ with: libusb-1.0-0-dev liblua5.2-dev libzita-resampler-dev libva-dev \ libavcodec-dev libavformat-dev libswscale-dev libavresample-dev \ libmovit-dev libegl1-mesa-dev libasound2-dev libx264-dev libbmusb-dev \ - protobuf-compiler libprotobuf-dev + protobuf-compiler libprotobuf-dev libpci-dev Exceptions as of October 2016: diff --git a/context.cpp b/context.cpp index 36fa2ea..e181be7 100644 --- a/context.cpp +++ b/context.cpp @@ -1,4 +1,10 @@ +#include #include +extern "C" { +#include +} + +#include #include #include @@ -7,16 +13,100 @@ #include QGLWidget *global_share_widget = nullptr; +bool using_egl = false; + +using namespace std; + +namespace { + +string get_pci_device_name(const char *node_name) +{ + char vendor_path[256]; + snprintf(vendor_path, sizeof(vendor_path), "/sys/class/drm/%s/device/vendor", node_name); + FILE *vendor_file = fopen(vendor_path, "r"); + if (vendor_file == nullptr) { + return "could not look up vendor ID"; + } + int vendor; + if (fscanf(vendor_file, "%i", &vendor) != 1) { + fclose(vendor_file); + return "could not parse vendor ID"; + } + fclose(vendor_file); + + char device_path[256]; + snprintf(device_path, sizeof(device_path), "/sys/class/drm/%s/device/device", node_name); + FILE *device_file = fopen(device_path, "r"); + if (device_file == nullptr) { + return "could not look up device ID"; + } + int device; + if (fscanf(device_file, "%i", &device) != 1) { + fclose(device_file); + return "could not parse device ID"; + } + fclose(device_file); + + pci_access *pci = pci_alloc(); + if (pci == nullptr) { + return "could not init libpci"; + } + pci_init(pci); + + char buf[256]; + const char *name = pci_lookup_name(pci, buf, sizeof(buf), PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, vendor, device); + pci_cleanup(pci); + + if (name == nullptr) { + snprintf(buf, sizeof(buf), "%04x:%04x", vendor, device); + } + return buf; +} + +void print_available_drm_nodes() +{ + glob_t g; + int err = glob("/dev/dri/renderD*", 0, nullptr, &g); // TODO: Accept /dev/dri/card*, too? + if (err != 0) { + fprintf(stderr, "Couldn't list render nodes (%s).\n", strerror(errno)); + return; + } + + if (g.gl_pathc == 0) { + fprintf(stderr, "\n"); + fprintf(stderr, "No render nodes found in /dev/dri.\n"); + } else { + fprintf(stderr, "Available devices (these may or may not support VA-API encoding):\n\n"); + for (size_t i = 0; i < g.gl_pathc; ++i) { + const char *node_name = basename(g.gl_pathv[i]); + fprintf(stderr, " %s (%s)\n", g.gl_pathv[i], get_pci_device_name(node_name).c_str()); + } + } + + globfree(&g); +} + +} // namespace QSurface *create_surface(const QSurfaceFormat &format) { QOffscreenSurface *surface = new QOffscreenSurface; surface->setFormat(format); -// QWindow *surface = new QWindow; surface->create(); if (!surface->isValid()) { - printf("ERROR: surface not valid!\n"); -// abort(); + fprintf(stderr, "ERROR: surface not valid!\n"); + if (using_egl) { + fprintf(stderr, "\n\n"); + fprintf(stderr, "OpenGL initialization failed. This is most likely because your driver does not\n"); + fprintf(stderr, "support EGL (e.g. NVIDIA drivers). You can turn off EGL by specifying the\n"); + fprintf(stderr, "VA-API path directly, assuming you have another GPU with VA-API support\n"); + fprintf(stderr, "(typically an integrated Intel GPU -- note that it you might need to manually\n"); + fprintf(stderr, "enable it in the BIOS, as it might be turned off when a discrete GPU is detected).\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Specify the VA-API device using “--va-display /dev/dri/”.\n"); + print_available_drm_nodes(); + } + exit(1); } return surface; } diff --git a/context.h b/context.h index 9b72eaf..13dbf24 100644 --- a/context.h +++ b/context.h @@ -7,6 +7,7 @@ class QOpenGLContext; class QSurfaceFormat; class QGLWidget; +extern bool using_egl; extern QGLWidget *global_share_widget; QSurface *create_surface(const QSurfaceFormat &format); QSurface *create_surface_with_same_format(const QSurface *surface); diff --git a/main.cpp b/main.cpp index e2d2cec..e156c59 100644 --- a/main.cpp +++ b/main.cpp @@ -28,6 +28,7 @@ int main(int argc, char *argv[]) // We normally use EGL for zerocopy, but if we use VA against DRM // instead of against X11, we turn it off, and then don't need EGL. setenv("QT_XCB_GL_INTEGRATION", "xcb_egl", 0); + using_egl = true; } setlinebuf(stdout); av_register_all(); -- 2.39.2