backend: add preliminary support for driver detection

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-04-20 00:21:38 +01:00
parent a2d0d5c826
commit 685a583f84
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
7 changed files with 132 additions and 1 deletions

View File

@ -5,6 +5,7 @@
#include <stdbool.h>
#include "driver.h"
#include "compiler.h"
#include "kernel.h"
#include "region.h"
@ -176,6 +177,9 @@ struct backend_operations {
// =========== Hooks ============
/// Let the backend hook into the event handling queue
// =========== Misc ============
/// Return the driver that is been used by the backend
enum driver (*detect_driver)(backend_t *backend_data);
};
typedef backend_t *(*backend_init_fn)(session_t *ps)attr_nonnull(1);

62
src/backend/driver.c Normal file
View File

@ -0,0 +1,62 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#include <xcb/randr.h>
#include <xcb/xcb.h>
#include "backend/backend.h"
#include "backend/driver.h"
#include "common.h"
enum driver detect_driver(xcb_connection_t *c, backend_t *backend_data, xcb_window_t window) {
enum driver ret = 0;
// First we try doing backend agnostic detection using RANDR
// There's no way to query the X server about what driver is loaded, so RANDR is
// our best shot.
auto randr_version = xcb_randr_query_version_reply(
c, xcb_randr_query_version(c, XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION),
NULL);
if (randr_version &&
(randr_version->major_version > 1 || randr_version->minor_version >= 4)) {
auto r = xcb_randr_get_providers_reply(
c, xcb_randr_get_providers(c, window), NULL);
if (r == NULL) {
log_warn("Failed to get RANDR providers");
return 0;
}
auto providers = xcb_randr_get_providers_providers(r);
for (auto i = 0; i < xcb_randr_get_providers_providers_length(r); i++) {
auto r2 = xcb_randr_get_provider_info_reply(
c, xcb_randr_get_provider_info(c, providers[i], r->timestamp), NULL);
if (r2 == NULL) {
continue;
}
if (r2->num_outputs == 0) {
free(r2);
continue;
}
auto name = xcb_randr_get_provider_info_name(r2);
if (strcasestr(name, "modesetting") != NULL) {
ret |= DRIVER_MODESETTING;
} else if (strcasestr(name, "Radeon") != NULL) {
// Be conservative, add both radeon drivers
ret |= DRIVER_AMDGPU | DRIVER_RADEON;
} else if (strcasestr(name, "NVIDIA") != NULL) {
ret |= DRIVER_NVIDIA;
} else if (strcasestr(name, "nouveau") != NULL) {
ret |= DRIVER_NOUVEAU;
} else if (strcasestr(name, "Intel") != NULL) {
ret |= DRIVER_INTEL;
}
}
free(r);
}
// If the backend supports driver detection, use that as well
if (backend_data && backend_data->ops->detect_driver) {
ret |= backend_data->ops->detect_driver(backend_data);
}
return ret;
}

55
src/backend/driver.h Normal file
View File

@ -0,0 +1,55 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#pragma once
#include <stdio.h>
#include <xcb/xcb.h>
struct session;
struct backend_base;
/// A list of possible drivers.
/// The driver situation is a bit complicated. There are two drivers we care about: the
/// DDX, and the OpenGL driver. They are usually paired, but not always, since there is
/// also the generic modesetting driver.
/// This enum represents _both_ drivers.
enum driver {
DRIVER_AMDGPU = 1, // AMDGPU for DDX, radeonsi for OpenGL
DRIVER_RADEON = 2, // ATI for DDX, mesa r600 for OpenGL
DRIVER_FGLRX = 4,
DRIVER_NVIDIA = 8,
DRIVER_NOUVEAU = 16,
DRIVER_INTEL = 32,
DRIVER_MODESETTING = 64,
};
/// Return a list of drivers currently in use by the X server.
/// Note, this is a best-effort test, so no guarantee all drivers will be detected.
enum driver detect_driver(xcb_connection_t *, struct backend_base *, xcb_window_t);
// Print driver names to stdout, for diagnostics
static inline void print_drivers(enum driver drivers) {
if (drivers & DRIVER_AMDGPU) {
printf("AMDGPU, ");
}
if (drivers & DRIVER_RADEON) {
printf("Radeon, ");
}
if (drivers & DRIVER_FGLRX) {
printf("fglrx, ");
}
if (drivers & DRIVER_NVIDIA) {
printf("NVIDIA, ");
}
if (drivers & DRIVER_NOUVEAU) {
printf("nouveau, ");
}
if (drivers & DRIVER_INTEL) {
printf("Intel, ");
}
if (drivers & DRIVER_MODESETTING) {
printf("modesetting, ");
}
printf("\b\b \n");
}

View File

@ -1,5 +1,5 @@
# enable xrender
srcs += [ files('backend_common.c', 'xrender/xrender.c', 'backend.c') ]
srcs += [ files('backend_common.c', 'xrender/xrender.c', 'backend.c', 'driver.c') ]
# enable opengl
if get_option('opengl')

View File

@ -78,6 +78,7 @@
// FIXME This list of includes should get shorter
#include "backend/backend.h"
#include "backend/driver.h"
#include "compiler.h"
#include "config.h"
#include "kernel.h"
@ -294,6 +295,7 @@ typedef struct session {
ev_signal int_signal;
/// backend data
backend_t *backend_data;
enum driver drivers;
/// libev mainloop
struct ev_loop *loop;

View File

@ -1311,6 +1311,9 @@ static bool redir_start(session_t *ps) {
ps->redirected = true;
// Re-detect driver since we now have a backend
ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root);
root_damaged(ps);
// Repaint the whole screen
@ -1985,6 +1988,8 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
// of OpenGL context.
init_overlay(ps);
ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root);
// Initialize filters, must be preceded by OpenGL context creation
if (!ps->o.experimental_backends && !init_render(ps)) {
log_fatal("Failed to initialize the backend");

View File

@ -4,6 +4,7 @@
#include <stdio.h>
#include <xcb/xcb.h>
#include "backend/driver.h"
#include "diagnostic.h"
#include "config.h"
#include "common.h"
@ -21,6 +22,8 @@ void print_diagnostics(session_t *ps, const char *config_file) {
printf("* Fast Math: Yes\n");
#endif
printf("* Config file used: %s\n", config_file ?: "None");
printf("\n### Drivers (inaccurate):\n\n");
print_drivers(ps->drivers);
}
// vim: set noet sw=8 ts=8 :