]> git.sesse.net Git - nageru/blob - context.cpp
Add a CORS policy to the channel endpoints, so that external applications can query...
[nageru] / context.cpp
1 #include <glob.h>
2 #include <stdio.h>
3 extern "C" {
4 #include <pci/pci.h>
5 }
6
7 #include <string>
8
9 #include <QGL>
10 #include <QOffscreenSurface>
11 #include <QOpenGLContext>
12 #include <QSurface>
13 #include <QSurfaceFormat>
14
15 QGLWidget *global_share_widget = nullptr;
16 bool using_egl = false;
17
18 using namespace std;
19
20 namespace {
21
22 string get_pci_device_name(const char *node_name)
23 {
24         char vendor_path[256];
25         snprintf(vendor_path, sizeof(vendor_path), "/sys/class/drm/%s/device/vendor", node_name);
26         FILE *vendor_file = fopen(vendor_path, "r");
27         if (vendor_file == nullptr) {
28                 return "could not look up vendor ID";
29         }
30         int vendor;
31         if (fscanf(vendor_file, "%i", &vendor) != 1) {
32                 fclose(vendor_file);
33                 return "could not parse vendor ID";
34         }
35         fclose(vendor_file);
36
37         char device_path[256];
38         snprintf(device_path, sizeof(device_path), "/sys/class/drm/%s/device/device", node_name);
39         FILE *device_file = fopen(device_path, "r");
40         if (device_file == nullptr) {
41                 return "could not look up device ID";
42         }
43         int device;
44         if (fscanf(device_file, "%i", &device) != 1) {
45                 fclose(device_file);
46                 return "could not parse device ID";
47         }
48         fclose(device_file);
49
50         pci_access *pci = pci_alloc();
51         if (pci == nullptr) {
52                 return "could not init libpci";
53         }
54         pci_init(pci);
55
56         char buf[256];
57         const char *name = pci_lookup_name(pci, buf, sizeof(buf), PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, vendor, device);
58         pci_cleanup(pci);
59
60         if (name == nullptr) {
61                 snprintf(buf, sizeof(buf), "%04x:%04x", vendor, device);
62         }
63         return buf;
64 }
65
66 void print_available_drm_nodes()
67 {
68         glob_t g;
69         int err = glob("/dev/dri/renderD*", 0, nullptr, &g);  // TODO: Accept /dev/dri/card*, too?
70         if (err != 0) {
71                 fprintf(stderr, "Couldn't list render nodes (%s).\n", strerror(errno));
72                 return;
73         }
74
75         if (g.gl_pathc == 0) {
76                 fprintf(stderr, "\n");
77                 fprintf(stderr, "No render nodes found in /dev/dri.\n");
78         } else {
79                 fprintf(stderr, "Available devices (these may or may not support VA-API encoding):\n\n");
80                 for (size_t i = 0; i < g.gl_pathc; ++i) {
81                         const char *node_name = basename(g.gl_pathv[i]);
82                         fprintf(stderr, "  %s (%s)\n", g.gl_pathv[i], get_pci_device_name(node_name).c_str());
83                 }
84         }
85
86         globfree(&g);
87 }
88
89 }  // namespace
90
91 QSurface *create_surface(const QSurfaceFormat &format)
92 {
93         QOffscreenSurface *surface = new QOffscreenSurface;
94         surface->setFormat(format);
95         surface->create();
96         if (!surface->isValid()) {
97                 fprintf(stderr, "ERROR: surface not valid!\n");
98                 if (using_egl) {
99                         fprintf(stderr, "\n\n");
100                         fprintf(stderr, "OpenGL initialization failed. This is most likely because your driver does not\n");
101                         fprintf(stderr, "support EGL (e.g. NVIDIA drivers). You can turn off EGL by specifying the\n");
102                         fprintf(stderr, "VA-API path directly, assuming you have another GPU with VA-API support\n");
103                         fprintf(stderr, "(typically an integrated Intel GPU -- note that it you might need to manually\n");
104                         fprintf(stderr, "enable it in the BIOS, as it might be turned off when a discrete GPU is detected).\n");
105                         fprintf(stderr, "\n");
106                         fprintf(stderr, "Specify the VA-API device using “--va-display /dev/dri/<node>”.\n");
107                         print_available_drm_nodes();
108                 }
109                 exit(1);
110         }
111         return surface;
112 }
113
114 QSurface *create_surface_with_same_format(const QSurface *surface)
115 {
116         return create_surface(surface->format());
117 }
118
119 QOpenGLContext *create_context(const QSurface *surface)
120 {
121         QOpenGLContext *context = new QOpenGLContext;
122         context->setShareContext(global_share_widget->context()->contextHandle());
123         context->setFormat(surface->format());
124         context->create();
125         return context;
126 }
127
128 bool make_current(QOpenGLContext *context, QSurface *surface)
129 {
130         return context->makeCurrent(surface);
131 }
132
133 void delete_context(QOpenGLContext *context)
134 {
135         delete context;
136 }