libobs,libobs-opengl,libobs-d3d11: Add opengl gs_enum_adapters

This adds gs_enum_adapters and gs_get_adapter_count to the opengl
backend and promotes these to multiplatform graphics functions.

However we need to make an internal device change, device_enum_adapters
must pass in the current device on opengl to ensure that adapter #0 is
the display adapter. We do this to avoid changes to plugins already
checking against obs_video_info.adapter which is always 0 and expected
to be the device OBS was initialized on.

The actual implementation reports the dri render node (or /Software).
This allows plugins to query non-video features of the adapters like
VA-API/NVENC/etc or other cross device functionality. `/Software` is
chosen to avoid opening random files in the current directory if its
passed along as a file path like the regular dri render nodes.
This commit is contained in:
Kurt Kartaltepe 2024-01-27 00:44:31 -08:00 committed by Lain
parent 477c3be050
commit 3e49e89611
12 changed files with 111 additions and 17 deletions

View file

@ -1016,10 +1016,13 @@ EnumD3DAdapters(bool (*callback)(void *, const char *, uint32_t), void *param)
}
}
bool device_enum_adapters(bool (*callback)(void *param, const char *name,
bool device_enum_adapters(gs_device_t *device,
bool (*callback)(void *param, const char *name,
uint32_t id),
void *param)
{
UNUSED_PARAMETER(device);
try {
EnumD3DAdapters(callback, param);
return true;

View file

@ -204,6 +204,53 @@ struct gs_texture *gl_egl_create_texture_from_eglimage(
return texture;
}
bool gl_egl_enum_adapters(EGLDisplay display,
bool (*callback)(void *param, const char *name,
uint32_t id),
void *param)
{
EGLDeviceEXT display_dev;
if (eglQueryDisplayAttribEXT(display, EGL_DEVICE_EXT,
(EGLAttrib *)&display_dev) &&
eglGetError() == EGL_SUCCESS) {
const char *display_node = eglQueryDeviceStringEXT(
display_dev, EGL_DRM_RENDER_NODE_FILE_EXT);
if (eglGetError() != EGL_SUCCESS || display_node == NULL) {
display_node = "/Software";
}
if (!callback(param, display_node, 0)) {
return true;
}
}
EGLint num_devices = 0;
EGLDeviceEXT devices[32];
if (!eglQueryDevicesEXT(32, devices, &num_devices)) {
eglGetError();
return true;
}
for (int i = 0; i < num_devices; i++) {
const char *node = eglQueryDeviceStringEXT(
devices[i], EGL_DRM_RENDER_NODE_FILE_EXT);
if (node == NULL || eglGetError() != EGL_SUCCESS) {
// Do not enumerate additional software renderers.
continue;
}
if (!callback(param, node, i + 1)) {
return true;
}
}
return true;
}
uint32_t gs_get_adapter_count()
{
EGLint num_devices = 0;
eglQueryDevicesEXT(0, NULL, &num_devices);
return 1 + num_devices; // Display + devices.
}
struct gs_texture *
gl_egl_create_dmabuf_image(EGLDisplay egl_display, unsigned int width,
unsigned int height, uint32_t drm_format,

View file

@ -27,3 +27,9 @@ gl_egl_create_texture_from_pixmap(EGLDisplay egl_display, uint32_t width,
uint32_t height,
enum gs_color_format color_format,
EGLint target, EGLClientBuffer pixmap);
bool gl_egl_enum_adapters(EGLDisplay display,
bool (*callback)(void *param, const char *name,
uint32_t id),
void *param);
uint32_t gs_get_adapter_count();

View file

@ -95,6 +95,14 @@ extern void device_leave_context(gs_device_t *device)
gl_vtable->device_leave_context(device);
}
extern bool device_enum_adapters(gs_device_t *device,
bool (*callback)(void *param, const char *name,
uint32_t id),
void *param)
{
return gl_vtable->device_enum_adapters(device, callback, param);
}
extern void *device_get_device_obj(gs_device_t *device)
{
return gl_vtable->device_get_device_obj(device);

View file

@ -73,4 +73,9 @@ struct gl_winsys_vtable {
gs_device_t *device, uint32_t width, uint32_t height,
enum gs_color_format color_format, uint32_t target,
void *pixmap);
bool (*device_enum_adapters)(gs_device_t *device,
bool (*callback)(void *param,
const char *name,
uint32_t id),
void *param);
};

View file

@ -397,6 +397,15 @@ static struct gs_texture *gl_wayland_egl_device_texture_create_from_pixmap(
return NULL;
}
static bool gl_wayland_egl_enum_adapters(gs_device_t *device,
bool (*callback)(void *param,
const char *name,
uint32_t id),
void *param)
{
return gl_egl_enum_adapters(device->plat->display, callback, param);
}
static const struct gl_winsys_vtable egl_wayland_winsys_vtable = {
.windowinfo_create = gl_wayland_egl_windowinfo_create,
.windowinfo_destroy = gl_wayland_egl_windowinfo_destroy,
@ -420,6 +429,7 @@ static const struct gl_winsys_vtable egl_wayland_winsys_vtable = {
gl_wayland_egl_device_query_dmabuf_modifiers_for_format,
.device_texture_create_from_pixmap =
gl_wayland_egl_device_texture_create_from_pixmap,
.device_enum_adapters = gl_wayland_egl_enum_adapters,
};
const struct gl_winsys_vtable *gl_wayland_egl_get_winsys_vtable(void)

View file

@ -612,6 +612,15 @@ static bool gl_x11_egl_device_query_dmabuf_modifiers_for_format(
plat->edisplay, drm_format, modifiers, n_modifiers);
}
static bool gl_x11_egl_enum_adapters(gs_device_t *device,
bool (*callback)(void *param,
const char *name,
uint32_t id),
void *param)
{
return gl_egl_enum_adapters(device->plat->edisplay, callback, param);
}
static const struct gl_winsys_vtable egl_x11_winsys_vtable = {
.windowinfo_create = gl_x11_egl_windowinfo_create,
.windowinfo_destroy = gl_x11_egl_windowinfo_destroy,
@ -635,6 +644,7 @@ static const struct gl_winsys_vtable egl_x11_winsys_vtable = {
gl_x11_egl_device_query_dmabuf_modifiers_for_format,
.device_texture_create_from_pixmap =
gl_x11_egl_device_texture_create_from_pixmap,
.device_enum_adapters = gl_x11_egl_enum_adapters,
};
const struct gl_winsys_vtable *gl_x11_egl_get_winsys_vtable(void)

View file

@ -25,7 +25,8 @@ extern "C" {
EXPORT const char *device_get_name(void);
EXPORT int device_get_type(void);
EXPORT bool device_enum_adapters(bool (*callback)(void *param, const char *name,
EXPORT bool device_enum_adapters(gs_device_t *device,
bool (*callback)(void *param, const char *name,
uint32_t id),
void *param);
EXPORT const char *device_preprocessor_name(void);

View file

@ -203,6 +203,8 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
GRAPHICS_IMPORT(device_debug_marker_begin);
GRAPHICS_IMPORT(device_debug_marker_end);
GRAPHICS_IMPORT_OPTIONAL(gs_get_adapter_count);
/* OSX/Cocoa specific functions */
#ifdef __APPLE__
GRAPHICS_IMPORT(device_shared_texture_available);
@ -222,7 +224,6 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
GRAPHICS_IMPORT_OPTIONAL(gs_duplicator_get_texture);
GRAPHICS_IMPORT_OPTIONAL(gs_duplicator_get_color_space);
GRAPHICS_IMPORT_OPTIONAL(gs_duplicator_get_sdr_white_level);
GRAPHICS_IMPORT_OPTIONAL(gs_get_adapter_count);
GRAPHICS_IMPORT_OPTIONAL(device_can_adapter_fast_clear);
GRAPHICS_IMPORT_OPTIONAL(device_texture_create_gdi);
GRAPHICS_IMPORT_OPTIONAL(gs_texture_get_dc);

View file

@ -26,7 +26,8 @@
struct gs_exports {
const char *(*device_get_name)(void);
int (*device_get_type)(void);
bool (*device_enum_adapters)(bool (*callback)(void *, const char *,
bool (*device_enum_adapters)(gs_device_t *device,
bool (*callback)(void *, const char *,
uint32_t),
void *);
const char *(*device_preprocessor_name)(void);
@ -291,6 +292,8 @@ struct gs_exports {
const float color[4]);
void (*device_debug_marker_end)(gs_device_t *device);
uint32_t (*gs_get_adapter_count)(void);
#ifdef __APPLE__
/* OSX/Cocoa specific functions */
gs_texture_t *(*device_texture_create_from_iosurface)(gs_device_t *dev,
@ -321,7 +324,6 @@ struct gs_exports {
gs_duplicator_t *duplicator);
float (*gs_duplicator_get_sdr_white_level)(gs_duplicator_t *duplicator);
uint32_t (*gs_get_adapter_count)(void);
bool (*device_can_adapter_fast_clear)(gs_device_t *device);
gs_texture_t *(*device_texture_create_gdi)(gs_device_t *device,

View file

@ -82,7 +82,8 @@ void gs_enum_adapters(bool (*callback)(void *param, const char *name,
return;
if (graphics->exports.device_enum_adapters) {
if (graphics->exports.device_enum_adapters(callback, param)) {
if (graphics->exports.device_enum_adapters(graphics->device,
callback, param)) {
return;
}
}
@ -2986,6 +2987,16 @@ bool gs_texture_create_p010(gs_texture_t **tex_y, gs_texture_t **tex_uv,
return true;
}
uint32_t gs_get_adapter_count(void)
{
if (!gs_valid("gs_get_adapter_count"))
return 0;
if (!thread_graphics->exports.gs_get_adapter_count)
return 0;
return thread_graphics->exports.gs_get_adapter_count();
}
#ifdef __APPLE__
/** Platform specific functions */
@ -3108,16 +3119,6 @@ bool gs_duplicator_update_frame(gs_duplicator_t *duplicator)
return thread_graphics->exports.gs_duplicator_update_frame(duplicator);
}
uint32_t gs_get_adapter_count(void)
{
if (!gs_valid("gs_get_adapter_count"))
return 0;
if (!thread_graphics->exports.gs_get_adapter_count)
return 0;
return thread_graphics->exports.gs_get_adapter_count();
}
bool gs_can_adapter_fast_clear(void)
{
if (!gs_valid("gs_can_adapter_fast_clear"))

View file

@ -525,6 +525,7 @@ struct gs_init_data {
EXPORT const char *gs_get_device_name(void);
EXPORT int gs_get_device_type(void);
EXPORT uint32_t gs_get_adapter_count(void);
EXPORT void gs_enum_adapters(bool (*callback)(void *param, const char *name,
uint32_t id),
void *param);
@ -929,7 +930,6 @@ EXPORT enum gs_color_space
gs_duplicator_get_color_space(gs_duplicator_t *duplicator);
EXPORT float gs_duplicator_get_sdr_white_level(gs_duplicator_t *duplicator);
EXPORT uint32_t gs_get_adapter_count(void);
EXPORT bool gs_can_adapter_fast_clear(void);
/** creates a windows GDI-lockable texture */