Skip to content

Commit

Permalink
[Linux] Add new option -dri_device. Use to force vsync on a specific …
Browse files Browse the repository at this point in the history
…dri device, e.g. "card0", "card1", etc., or "auto" for automatic selection (currently it will pick the first device with a valid connector."
  • Loading branch information
antonioginer committed Dec 2, 2023
1 parent be3e10f commit db3f2c6
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/osd/modules/lib/osdobj_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ const options_entry osd_options::s_option_entries[] =
{ OSDOPTION_AUTOSYNC, "1", core_options::option_type::BOOLEAN, "automatically enable syncrefresh if refresh difference is below syncrefresh_tolerance" },
{ OSDOPTION_AUTOFILTER, "1", core_options::option_type::BOOLEAN, "automatically set bilinear filtering with fractional stretching or interlaced " },
{ OSDOPTION_AUTOSTRETCH, "1", core_options::option_type::BOOLEAN, "automatically set scaling mode (integer or fractional) based on the selected video mode " },
{ OSDOPTION_DRI_DEVICE, OSDOPTVAL_AUTO, core_options::option_type::STRING, "Force drm video card for vsync (card0, card1, etc.) or auto for automatic." },
{ OSDOPTION_SCREEN_COMPOSITING, "0", core_options::option_type::BOOLEAN, "Readjust relative screen positions of a multi-display setup after mode switching (Linux)" },
{ OSDOPTION_SCREEN_REORDERING, "0", core_options::option_type::BOOLEAN, "Reallocates desktop multiple screens stacked vertically, so super-resolutions fit (Linux)" },
{ OSDOPTION_ALLOW_HW_REFRESH, "0", core_options::option_type::BOOLEAN, "Allow on-the-fly mode addition (Windows)" },
Expand Down
2 changes: 2 additions & 0 deletions src/osd/modules/lib/osdobj_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
#define OSDOPTION_AUTOSYNC "autosync"
#define OSDOPTION_AUTOFILTER "autofilter"
#define OSDOPTION_AUTOSTRETCH "autostretch"
#define OSDOPTION_DRI_DEVICE "dri_device"
#define OSDOPTION_SCREEN_COMPOSITING "screen_compositing"
#define OSDOPTION_SCREEN_REORDERING "screen_reordering"
#define OSDOPTION_ALLOW_HW_REFRESH "allow_hw_refresh"
Expand Down Expand Up @@ -203,6 +204,7 @@ class osd_options : public emu_options
bool autosync() const { return bool_value(OSDOPTION_AUTOSYNC); }
bool autofilter() const { return bool_value(OSDOPTION_AUTOFILTER); }
bool autostretch() const { return bool_value(OSDOPTION_AUTOSTRETCH); }
const char *dri_device() const { return value(OSDOPTION_DRI_DEVICE); }
bool screen_compositing() const { return bool_value(OSDOPTION_SCREEN_COMPOSITING); }
bool screen_reordering() const { return bool_value(OSDOPTION_SCREEN_REORDERING); }
bool allow_hw_refresh() const { return bool_value(OSDOPTION_ALLOW_HW_REFRESH); }
Expand Down
94 changes: 88 additions & 6 deletions src/osd/modules/render/draw13.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <list>

#ifdef SDLMAME_X11
#include <unistd.h>
// DRM
#include <xf86drm.h>
#include <xf86drmMode.h>
Expand Down Expand Up @@ -248,9 +249,10 @@ static inline bool is_transparent(const float &a)
//============================================================

#ifdef SDLMAME_X11
static int drm_open();
static int drm_open(const char *dri_device);
static void drm_waitvblank(int crtc);
static int fd = 0;
static const char* dri_device = nullptr;
#endif

//============================================================
Expand Down Expand Up @@ -482,7 +484,7 @@ int renderer_sdl2::create()
if (window().index() == 0 && video_config.syncrefresh && video_config.sync_mode != 0)
{
// Try to open DRM device
fd = drm_open();
fd = drm_open(dri_device);
if (fd != 0)
renderer_vsync = (video_config.sync_mode == 2 || video_config.sync_mode == 4)? true : false;
}
Expand Down Expand Up @@ -519,18 +521,94 @@ int renderer_sdl2::create()
// drm_open
//============================================================

static int drm_open()
static int drm_open(const char *dri_device)
{
int fd = 0;
const char *node = {"/dev/dri/card0"};
char dri_path[16];
char *node = dri_path;

// Dri device forced by user
if (strcmp(dri_device, "auto") != 0)
{
osd_printf_verbose("drm_open: %s for by user\n", dri_device);
snprintf(node, sizeof(dri_path), "/dev/dri/%s", dri_device);
}

// Automatic selection
else
{
// Get an array of drm devices to check
int num_devices = drmGetDevices2(0, NULL, 0);
if (num_devices <= 0)
{
osd_printf_error("drm_open: couldn't find any drm device\n");
return 0;
}

drmDevicePtr *devices = (drmDevicePtr*)calloc(num_devices, sizeof(drmDevicePtr));
if (drmGetDevices2(0, devices, num_devices) < 0)
{
osd_printf_error("drm_open: drmGetDevices2() failed\n");
return 0;
}

// Parse device list to find the first one with a valid connector
bool found = false;

for (int i = 0; i < num_devices; i++)
{
// Skip non-primary nodes
if (devices[i]->available_nodes & (1 << DRM_NODE_PRIMARY))
node = devices[i]->nodes[DRM_NODE_PRIMARY];

else continue;

fd = open(node, O_RDWR | O_CLOEXEC);
if (fd < 0)
{
osd_printf_error("drm_open: couldn't open %s\n", node);
continue;
}
drmModeRes *resources = drmModeGetResources(fd);
if (resources && resources->count_connectors > 0 && resources->count_encoders > 0 && resources->count_crtcs > 0)
{
for (int j = 0; j < resources->count_connectors; j++)
{
drmModeConnector *conn = drmModeGetConnector(fd, resources->connectors[j]);
if (!conn) continue;

// We found a valid connector, use it
if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0)
found = true;

drmModeFreeConnector(conn);
if (found) break;
}
}
drmModeFreeResources(resources);
close(fd);

if (found) break;
}

drmFreeDevices(devices, num_devices);
free(devices);

if (!found)
{
osd_printf_error("drm_open: couldn't find any device with a valid connector\n");
return 0;
}
}

fd = open(node, O_RDWR | O_CLOEXEC);
if (fd < 0)
{
fprintf(stderr, "cannot open %s\n", node);
osd_printf_error("drm_open: cannot open %s\n", node);
return 0;
}
osd_printf_verbose("%s successfully opened\n", node);

osd_printf_verbose("drm_open: %s successfully opened\n", node);
return fd;
}

Expand Down Expand Up @@ -1125,6 +1203,10 @@ int video_sdl2::init(osd_interface &osd, osd_options const &options)
}
}

#ifdef SDLMAME_X11
dri_device = dynamic_cast<sdl_options const &>(options).dri_device();
#endif

return 0;
}

Expand Down
92 changes: 86 additions & 6 deletions src/osd/modules/render/drawogl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ typedef uint64_t HashT;


#ifdef SDLMAME_X11
#include <unistd.h>
// DRM
#include <xf86drm.h>
#include <xf86drmMode.h>
Expand Down Expand Up @@ -563,9 +564,10 @@ static int glsl_shader_feature = glsl_shader_info::FEAT_PLAIN; // FIXME: why is
bool renderer_ogl::s_shown_video_info = false;

#ifdef SDLMAME_X11
static int drm_open();
static int drm_open(const char *dri_device);
static void drm_waitvblank(int crtc);
static int fd = 0;
static const char* dri_device = nullptr;
#endif

//============================================================
Expand Down Expand Up @@ -780,7 +782,7 @@ int renderer_ogl::create()
if (window().index() == 0 && video_config.syncrefresh && video_config.sync_mode != 0)
{
// Try to open DRM device
fd = drm_open();
fd = drm_open(dri_device);
if (fd != 0)
m_gl_context->set_swap_interval((video_config.sync_mode == 2 || video_config.sync_mode == 4)? 1 : 0);
}
Expand Down Expand Up @@ -816,18 +818,94 @@ int renderer_ogl::create()
// drm_open
//============================================================

static int drm_open()
static int drm_open(const char *dri_device)
{
int fd = 0;
const char *node = {"/dev/dri/card0"};
char dri_path[16];
char *node = dri_path;

// Dri device forced by user
if (strcmp(dri_device, "auto") != 0)
{
osd_printf_verbose("drm_open: %s for by user\n", dri_device);
snprintf(node, sizeof(dri_path), "/dev/dri/%s", dri_device);
}

// Automatic selection
else
{
// Get an array of drm devices to check
int num_devices = drmGetDevices2(0, NULL, 0);
if (num_devices <= 0)
{
osd_printf_error("drm_open: couldn't find any drm device\n");
return 0;
}

drmDevicePtr *devices = (drmDevicePtr*)calloc(num_devices, sizeof(drmDevicePtr));
if (drmGetDevices2(0, devices, num_devices) < 0)
{
osd_printf_error("drm_open: drmGetDevices2() failed\n");
return 0;
}

// Parse device list to find the first one with a valid connector
bool found = false;

for (int i = 0; i < num_devices; i++)
{
// Skip non-primary nodes
if (devices[i]->available_nodes & (1 << DRM_NODE_PRIMARY))
node = devices[i]->nodes[DRM_NODE_PRIMARY];

else continue;

fd = open(node, O_RDWR | O_CLOEXEC);
if (fd < 0)
{
osd_printf_error("drm_open: couldn't open %s\n", node);
continue;
}
drmModeRes *resources = drmModeGetResources(fd);
if (resources && resources->count_connectors > 0 && resources->count_encoders > 0 && resources->count_crtcs > 0)
{
for (int j = 0; j < resources->count_connectors; j++)
{
drmModeConnector *conn = drmModeGetConnector(fd, resources->connectors[j]);
if (!conn) continue;

// We found a valid connector, use it
if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0)
found = true;

drmModeFreeConnector(conn);
if (found) break;
}
}
drmModeFreeResources(resources);
close(fd);

if (found) break;
}

drmFreeDevices(devices, num_devices);
free(devices);

if (!found)
{
osd_printf_error("drm_open: couldn't find any device with a valid connector\n");
return 0;
}
}

fd = open(node, O_RDWR | O_CLOEXEC);
if (fd < 0)
{
fprintf(stderr, "cannot open %s\n", node);
osd_printf_error("drm_open: cannot open %s\n", node);
return 0;
}
osd_printf_verbose("%s successfully opened\n", node);

osd_printf_verbose("drm_open: %s successfully opened\n", node);
return fd;
}

Expand Down Expand Up @@ -3106,6 +3184,8 @@ int video_opengl::init(osd_interface &osd, osd_options const &options)
osd_printf_verbose("Using SDL multi-window OpenGL driver (SDL 2.0+)\n");
#endif // defined(OSD_WINDOWS)

dri_device = dynamic_cast<sdl_options const &>(options).dri_device();

return 0;
}

Expand Down

0 comments on commit db3f2c6

Please sign in to comment.