]> git.sesse.net Git - nageru/commitdiff
If EGL initialization fails, print a friendlier error message.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 31 Oct 2016 22:43:40 +0000 (23:43 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 31 Oct 2016 22:43:40 +0000 (23:43 +0100)
The libpci dependency might be a bit overkill, but it really
helps friendliness in an otherwise pretty inscrutinable case.

Makefile
README
context.cpp
context.h
main.cpp

index 968fa63df1bcc0e699e31158e0e0c63b7af947fb..6b7925402c2c785fbf6c07f6dbc1a40bd57748f8 100644 (file)
--- 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 02f02eb03fdb3c8298a7762808224afecd9c9b95..43e68c4fb2591653e93dc49028baebb9694d05d8 100644 (file)
--- 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:
 
index 36fa2ea7221c8a971541e43d944bbd966f8b7eeb..e181be7cecb644e39faa5071d61ebe9057a16190 100644 (file)
@@ -1,4 +1,10 @@
+#include <glob.h>
 #include <stdio.h>
+extern "C" {
+#include <pci/pci.h>
+}
+
+#include <string>
 
 #include <QGL>
 #include <QOffscreenSurface>
 #include <QSurfaceFormat>
 
 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/<node>”.\n");
+                       print_available_drm_nodes();
+               }
+               exit(1);
        }
        return surface;
 }
index 9b72eaf9f1d79be4b0b6ec92c5d455acab7ab2a7..13dbf248f8cd4289b781de3b2e0d000803529ba9 100644 (file)
--- 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);
index e2d2cec4ee42c46f12527c9f29be3972302cb0ea..e156c5964722755872d218696686d7cb81a7bec9 100644 (file)
--- 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();