Skip to content

Commit

Permalink
feat(ui): list available displays with select
Browse files Browse the repository at this point in the history
  • Loading branch information
Hazer committed May 1, 2024
1 parent 7fb8c76 commit 607eae1
Show file tree
Hide file tree
Showing 11 changed files with 320 additions and 4 deletions.
6 changes: 6 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ namespace config {
bool install_steam_drivers;
};

struct display_options_t {
int id;
std::string name;
bool is_primary_display;
};

constexpr int ENCRYPTION_MODE_NEVER = 0; // Never use video encryption, even if the client supports it
constexpr int ENCRYPTION_MODE_OPPORTUNISTIC = 1; // Use video encryption if available, but stream without it if not supported
constexpr int ENCRYPTION_MODE_MANDATORY = 2; // Always use video encryption and refuse clients that can't encrypt
Expand Down
10 changes: 10 additions & 0 deletions src/confighttp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,16 @@ namespace confighttp {
outputTree.put("platform", SUNSHINE_PLATFORM);
outputTree.put("version", PROJECT_VER);

pt::ptree displays;
for (const auto &[id, name, is_primary_display] : platf::display_options()) {
pt::ptree display_value;
display_value.put("id", id);
display_value.put("name", name);
display_value.put("is_primary", is_primary_display);
displays.push_front(std::make_pair(std::to_string(id), display_value));
}
outputTree.push_back(std::make_pair("displays", displays));

auto vars = config::parse_config(file_handler::read_file(config::sunshine.config_file.c_str()));

for (auto &[name, value] : vars) {
Expand Down
3 changes: 3 additions & 0 deletions src/platform/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,9 @@ namespace platf {
std::vector<std::string>
display_names(mem_type_e hwdevice_type);

std::vector<config::display_options_t>
display_options();

/**
* @brief Returns if GPUs/drivers have changed since the last call to this function.
* @return `true` if a change has occurred or if it is unknown whether a change occurred.
Expand Down
32 changes: 32 additions & 0 deletions src/platform/linux/cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1049,4 +1049,36 @@ namespace platf {

return display_names;
}

std::vector<config::display_options_t>
nvfbc_display_options() {
if (cuda::init() || cuda::nvfbc::init()) {
return {};
}

std::vector<config::display_options_t> display_options;

auto handle = cuda::nvfbc::handle_t::make();
if (!handle) {
return {};
}

auto status_params = handle->status();
if (!status_params) {
return {};
}

for (auto x = 0; x < status_params->dwOutputNum; ++x) {
auto &output = status_params->outputs[x];
std::string name = output.name;
auto option = config::display_options_t {
x,
name + ", dwID: " + std::to_string(output.dwId),
false // TODO: Find proper way of doing it, found no way of checking for primary display myself
};
display_options.emplace_back(option);
}

return display_options;
}
} // namespace platf
72 changes: 72 additions & 0 deletions src/platform/linux/kmsgrab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1747,4 +1747,76 @@ namespace platf {
return display_names;
}

std::vector<config::display_options_t>
kms_display_options() {
int count = 0;

if (!fs::exists("/dev/dri")) {
return {};
}

if (!gbm::create_device) {
return {};
}

std::vector<config::display_options_t> display_options;

kms::conn_type_count_t conn_type_count;

fs::path card_dir { "/dev/dri"sv };
for (auto &entry : fs::directory_iterator { card_dir }) {
auto file = entry.path().filename();

auto filestring = file.generic_string();
if (std::string_view { filestring }.substr(0, 4) != "card"sv) {
continue;
}

kms::card_t card;
if (card.init(entry.path().c_str())) {
continue;
}

auto crtc_to_monitor = kms::map_crtc_to_monitor(card.monitors(conn_type_count));

auto end = std::end(card);
for (auto plane = std::begin(card); plane != end; ++plane) {
// Skip unused planes
if (!plane->fb_id) {
continue;
}

if (card.is_cursor(plane->plane_id)) {
continue;
}

auto fb = card.fb(plane.get());
if (!fb) {
continue;
}

if (!fb->handles[0]) {
break;
}

// This appears to return the offset of the monitor
auto crtc = card.crtc(plane->crtc_id);
if (!crtc) {
continue;
}

auto monitor = crtc_to_monitor[plane->crtc_id];

auto option = config::display_options_t {
count++,
std::to_string(count) + ", type: " + std::to_string(monitor.index), // TODO: Get real display name
false // TODO: Dunno how to find if it is primary
};
display_options.emplace_back(option);
}
}

return display_options;
}

} // namespace platf
25 changes: 25 additions & 0 deletions src/platform/linux/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,8 @@ namespace platf {
#ifdef SUNSHINE_BUILD_CUDA
std::vector<std::string>
nvfbc_display_names();
std::vector<config::display_options_t>
nvfbc_display_options();
std::shared_ptr<display_t>
nvfbc_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);

Expand All @@ -789,6 +791,8 @@ namespace platf {
#ifdef SUNSHINE_BUILD_WAYLAND
std::vector<std::string>
wl_display_names();
std::vector<config::display_options_t>
wl_display_options();
std::shared_ptr<display_t>
wl_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);

Expand All @@ -801,6 +805,8 @@ namespace platf {
#ifdef SUNSHINE_BUILD_DRM
std::vector<std::string>
kms_display_names(mem_type_e hwdevice_type);
std::vector<config::display_options_t>
kms_display_options();
std::shared_ptr<display_t>
kms_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);

Expand All @@ -813,6 +819,8 @@ namespace platf {
#ifdef SUNSHINE_BUILD_X11
std::vector<std::string>
x11_display_names();
std::vector<config::display_options_t>
x11_display_options();
std::shared_ptr<display_t>
x11_display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config);

Expand Down Expand Up @@ -840,6 +848,23 @@ namespace platf {
return {};
}

std::vector<config::display_options_t>
display_options() {
#ifdef SUNSHINE_BUILD_CUDA
if (sources[source::NVFBC]) return nvfbc_display_options();
#endif
#ifdef SUNSHINE_BUILD_WAYLAND
if (sources[source::WAYLAND]) return wl_display_options();
#endif
#ifdef SUNSHINE_BUILD_DRM
if (sources[source::KMS]) return kms_display_options();
#endif
#ifdef SUNSHINE_BUILD_X11
if (sources[source::X11]) return x11_display_options();
#endif
return {};
}

/**
* @brief Returns if GPUs/drivers have changed since the last call to this function.
* @return `true` if a change has occurred or if it is unknown whether a change occurred.
Expand Down
42 changes: 42 additions & 0 deletions src/platform/linux/wlgrab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,4 +454,46 @@ namespace platf {
return display_names;
}

std::vector<config::display_options_t>
wl_display_options() {
wl::display_t display;
if (display.init()) {
return {};
}

wl::interface_t interface;
interface.listen(display.registry());

display.roundtrip();

if (!interface[wl::interface_t::XDG_OUTPUT]) {
return {};
}

if (!interface[wl::interface_t::WLR_EXPORT_DMABUF]) {
return {};
}

for (auto &monitor : interface.monitors) {
monitor->listen(interface.output_manager);
}

display.roundtrip();

std::vector<config::display_options_t> display_options;

for (int x = 0; x < interface.monitors.size(); ++x) {
auto monitor = interface.monitors[x].get();

auto option = config::display_options_t {
x,
monitor->name + ": " + monitor->description,
false // TODO: Find proper way of doing it, found no way of checking for primary display myself
};
display_options.emplace_back(option);
}

return display_options;
}

} // namespace platf
40 changes: 40 additions & 0 deletions src/platform/linux/x11grab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ namespace platf {

namespace rr {
_FN(GetScreenResources, XRRScreenResources *, (Display * dpy, Window window));
_FN(GetOutputPrimary, RROutput, (Display * dpy, Window window));
_FN(GetOutputInfo, XRROutputInfo *, (Display * dpy, XRRScreenResources *resources, RROutput output));
_FN(GetCrtcInfo, XRRCrtcInfo *, (Display * dpy, XRRScreenResources *resources, RRCrtc crtc));
_FN(FreeScreenResources, void, (XRRScreenResources * resources));
Expand All @@ -86,6 +87,7 @@ namespace platf {

std::vector<std::tuple<dyn::apiproc *, const char *>> funcs {
{ (dyn::apiproc *) &GetScreenResources, "XRRGetScreenResources" },
{ (dyn::apiproc *) &GetOutputPrimary, "XRRGetOutputPrimary" },
{ (dyn::apiproc *) &GetOutputInfo, "XRRGetOutputInfo" },
{ (dyn::apiproc *) &GetCrtcInfo, "XRRGetCrtcInfo" },
{ (dyn::apiproc *) &FreeScreenResources, "XRRFreeScreenResources" },
Expand Down Expand Up @@ -836,6 +838,44 @@ namespace platf {
return names;
}

std::vector<config::display_options_t>
x11_display_options() {
if (load_x11() || load_xcb()) {
return {};
}

x11::xdisplay_t xdisplay { x11::OpenDisplay(nullptr) };
if (!xdisplay) {
return {};
}

auto xwindow = DefaultRootWindow(xdisplay.get());
screen_res_t screenr { x11::rr::GetScreenResources(xdisplay.get(), xwindow) };
int output = screenr->noutput;

auto main_display = x11::rr::GetOutputPrimary(xdisplay.get(), xwindow);

std::vector<config::display_options_t> display_options;

int monitor = 0;
for (int x = 0; x < output; ++x) {
output_info_t out_info { x11::rr::GetOutputInfo(xdisplay.get(), screenr.get(), screenr->outputs[x]) };
if (out_info) {
std::string name = out_info->name;
auto is_connected_value = (out_info->connection == RR_Connected) ? "true" : "false";
auto option = config::display_options_t {
monitor,
name + " connected: " + is_connected_value,
main_display == screenr->outputs[x]
};
display_options.emplace_back(option);
++monitor;
}
}

return display_options;
}

void
freeImage(XImage *p) {
XDestroyImage(p);
Expand Down
24 changes: 24 additions & 0 deletions src/platform/macos/display.mm
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,30 @@
return display_names;
}

std::vector<config::display_options_t>
display_options() {
__block std::vector<config::display_options_t> display_options;

auto display_array = [AVVideo displayNames];

auto main_display_id = CGMainDisplayID();
display_options.reserve([display_array count]);

[display_array enumerateObjectsUsingBlock:^(NSDictionary *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
NSNumber *display_id = obj[@"id"];
NSString *name = obj[@"displayName"];

auto option = config::display_options_t {
[display_id intValue],
name.UTF8String,
main_display_id == [display_id unsignedIntValue]
};
display_options.emplace_back(option);
}];

return display_options;
}

/**
* @brief Returns if GPUs/drivers have changed since the last call to this function.
* @return `true` if a change has occurred or if it is unknown whether a change occurred.
Expand Down
Loading

0 comments on commit 607eae1

Please sign in to comment.