X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=context.cpp;h=e181be7cecb644e39faa5071d61ebe9057a16190;hb=ffd68fbfb90242069af957f2a28908f0559f8348;hp=72275e9f9ba5db18d039e8c6e577356a6f9aa2b0;hpb=e18d9bad93d5bf766d52d0cb66db4c3d3f8a711b;p=nageru diff --git a/context.cpp b/context.cpp index 72275e9..e181be7 100644 --- a/context.cpp +++ b/context.cpp @@ -1,27 +1,126 @@ +#include #include -#include +extern "C" { +#include +} -#include +#include + +#include #include -#include +#include +#include +#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; } -QOpenGLContext *create_context() +QSurface *create_surface_with_same_format(const QSurface *surface) +{ + return create_surface(surface->format()); +} + +QOpenGLContext *create_context(const QSurface *surface) { QOpenGLContext *context = new QOpenGLContext; - context->setShareContext(QOpenGLContext::globalShareContext()); + context->setShareContext(global_share_widget->context()->contextHandle()); + context->setFormat(surface->format()); context->create(); return context; } @@ -30,3 +129,8 @@ bool make_current(QOpenGLContext *context, QSurface *surface) { return context->makeCurrent(surface); } + +void delete_context(QOpenGLContext *context) +{ + delete context; +}