Choose between x11grab and kmsgrab at runtime
This commit is contained in:
@@ -106,20 +106,28 @@ else()
|
|||||||
add_compile_definitions(SUNSHINE_PLATFORM="linux")
|
add_compile_definitions(SUNSHINE_PLATFORM="linux")
|
||||||
list(APPEND SUNSHINE_DEFINITIONS APPS_JSON="apps_linux.json")
|
list(APPEND SUNSHINE_DEFINITIONS APPS_JSON="apps_linux.json")
|
||||||
|
|
||||||
find_package(X11)
|
if(NOT DEFINED SUNSHINE_DISABLE_X11)
|
||||||
find_package(LIBDRM)
|
find_package(X11)
|
||||||
|
endif()
|
||||||
|
if(NOT DEFINED SUNSHINE_DISABLE_DRM)
|
||||||
|
find_package(LIBDRM)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(FFMPEG REQUIRED)
|
find_package(FFMPEG REQUIRED)
|
||||||
|
|
||||||
if(X11_FOUND)
|
if(X11_FOUND)
|
||||||
|
add_compile_definitions(SUNSHINE_BUILD_X11)
|
||||||
include_directories(${X11_INCLUDE_DIR})
|
include_directories(${X11_INCLUDE_DIR})
|
||||||
list(APPEND PLATFORM_TARGET_FILES sunshine/platform/linux/x11grab.cpp)
|
list(APPEND PLATFORM_TARGET_FILES sunshine/platform/linux/x11grab.cpp)
|
||||||
elseif(LIBDRM_FOUND)
|
endif()
|
||||||
|
if(LIBDRM_FOUND)
|
||||||
|
add_compile_definitions(SUNSHINE_BUILD_DRM)
|
||||||
include_directories(${LIBDRM_INCLUDE_DIRS})
|
include_directories(${LIBDRM_INCLUDE_DIRS})
|
||||||
list(APPEND PLATFORM_LIBRARIES ${LIBDRM_LIBRARIES})
|
list(APPEND PLATFORM_LIBRARIES ${LIBDRM_LIBRARIES})
|
||||||
list(APPEND PLATFORM_TARGET_FILES sunshine/platform/linux/kmsgrab.cpp)
|
list(APPEND PLATFORM_TARGET_FILES sunshine/platform/linux/kmsgrab.cpp)
|
||||||
list(APPEND SUNSHINE_DEFINITIONS EGL_NO_X11=1)
|
list(APPEND SUNSHINE_DEFINITIONS EGL_NO_X11=1)
|
||||||
else()
|
endif()
|
||||||
|
if(NOT X11_FOUND AND NOT LIBDRM_FOUND)
|
||||||
message(FATAL "Couldn't find either x11 or libdrm")
|
message(FATAL "Couldn't find either x11 or libdrm")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "sunshine/main.h"
|
#include "sunshine/main.h"
|
||||||
#include "sunshine/platform/common.h"
|
#include "sunshine/platform/common.h"
|
||||||
|
#include "sunshine/round_robin.h"
|
||||||
#include "sunshine/utility.h"
|
#include "sunshine/utility.h"
|
||||||
|
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
@@ -21,6 +22,102 @@ using plane_t = util::safe_ptr<drmModePlane, drmModeFreePlane>;
|
|||||||
using fb_t = util::safe_ptr<drmModeFB, drmModeFreeFB>;
|
using fb_t = util::safe_ptr<drmModeFB, drmModeFreeFB>;
|
||||||
using fb2_t = util::safe_ptr<drmModeFB2, drmModeFreeFB2>;
|
using fb2_t = util::safe_ptr<drmModeFB2, drmModeFreeFB2>;
|
||||||
|
|
||||||
|
class plane_it_t : public util::it_wrap_t<plane_t::element_type, plane_it_t> {
|
||||||
|
public:
|
||||||
|
plane_it_t(int fd, std::uint32_t *plane_p, std::uint32_t *end)
|
||||||
|
: fd { fd }, plane_p { plane_p }, end { end } {
|
||||||
|
inc();
|
||||||
|
}
|
||||||
|
|
||||||
|
plane_it_t(int fd, std::uint32_t *end)
|
||||||
|
: fd { fd }, plane_p { end }, end { end } {}
|
||||||
|
|
||||||
|
void inc() {
|
||||||
|
this->plane.reset();
|
||||||
|
|
||||||
|
for(; plane_p != end; ++plane_p) {
|
||||||
|
plane_t plane = drmModeGetPlane(fd, *plane_p);
|
||||||
|
|
||||||
|
if(!plane) {
|
||||||
|
BOOST_LOG(error) << "Couldn't get drm plane ["sv << (end - plane_p) << "]: "sv << strerror(errno);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this plane is unused
|
||||||
|
if(plane->fb_id) {
|
||||||
|
this->plane = util::make_shared<plane_t>(plane.release());
|
||||||
|
|
||||||
|
// One last increment
|
||||||
|
++plane_p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eq(const plane_it_t &other) const {
|
||||||
|
return plane_p == other.plane_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
plane_t::pointer get() {
|
||||||
|
return plane.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
std::uint32_t *plane_p;
|
||||||
|
std::uint32_t *end;
|
||||||
|
|
||||||
|
util::shared_t<plane_t> plane;
|
||||||
|
};
|
||||||
|
|
||||||
|
class card_t {
|
||||||
|
public:
|
||||||
|
int init(const char *path) {
|
||||||
|
fd.el = open(path, O_RDWR);
|
||||||
|
|
||||||
|
if(fd.el < 0) {
|
||||||
|
BOOST_LOG(error) << "Couldn't open: "sv << path << ": "sv << strerror(errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(drmSetClientCap(fd.el, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) {
|
||||||
|
BOOST_LOG(error) << "Couldn't expose some/all drm planes"sv;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
plane_res.reset(drmModeGetPlaneResources(fd.el));
|
||||||
|
if(!plane_res) {
|
||||||
|
BOOST_LOG(error) << "Couldn't get drm plane resources"sv;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_t fb(plane_t::pointer plane) {
|
||||||
|
return drmModeGetFB(fd.el, plane->fb_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
plane_t operator[](std::uint32_t index) {
|
||||||
|
return drmModeGetPlane(fd.el, plane_res->planes[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t count() {
|
||||||
|
return plane_res->count_planes;
|
||||||
|
}
|
||||||
|
|
||||||
|
plane_it_t begin() const {
|
||||||
|
return plane_it_t { fd.el, plane_res->planes, plane_res->planes + plane_res->count_planes };
|
||||||
|
}
|
||||||
|
|
||||||
|
plane_it_t end() const {
|
||||||
|
return plane_it_t { fd.el, plane_res->planes + plane_res->count_planes };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
egl::file_t fd;
|
||||||
|
plane_res_t plane_res;
|
||||||
|
};
|
||||||
|
|
||||||
struct kms_img_t : public img_t {
|
struct kms_img_t : public img_t {
|
||||||
~kms_img_t() override {
|
~kms_img_t() override {
|
||||||
delete[] data;
|
delete[] data;
|
||||||
@@ -28,6 +125,33 @@ struct kms_img_t : public img_t {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void print(plane_t::pointer plane, fb_t::pointer fb) {
|
||||||
|
BOOST_LOG(debug)
|
||||||
|
<< "x("sv << plane->x
|
||||||
|
<< ") y("sv << plane->y
|
||||||
|
<< ") crtc_x("sv << plane->crtc_x
|
||||||
|
<< ") crtc_y("sv << plane->crtc_y
|
||||||
|
<< ") crtc_id("sv << plane->crtc_id
|
||||||
|
<< ')';
|
||||||
|
|
||||||
|
BOOST_LOG(debug)
|
||||||
|
<< "Resolution: "sv << fb->width << 'x' << fb->height
|
||||||
|
<< ": Pitch: "sv << fb->pitch
|
||||||
|
<< ": bpp: "sv << fb->bpp
|
||||||
|
<< ": depth: "sv << fb->depth;
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
ss << "Format ["sv;
|
||||||
|
std::for_each_n(plane->formats, plane->count_formats - 1, [&ss](auto format) {
|
||||||
|
ss << util::view(format) << ", "sv;
|
||||||
|
});
|
||||||
|
|
||||||
|
ss << util::view(plane->formats[plane->count_formats - 1]) << ']';
|
||||||
|
|
||||||
|
BOOST_LOG(debug) << ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
class display_t : public platf::display_t {
|
class display_t : public platf::display_t {
|
||||||
public:
|
public:
|
||||||
display_t() : platf::display_t() {}
|
display_t() : platf::display_t() {}
|
||||||
@@ -41,88 +165,59 @@ public:
|
|||||||
delay = std::chrono::nanoseconds { 1s } / framerate;
|
delay = std::chrono::nanoseconds { 1s } / framerate;
|
||||||
|
|
||||||
constexpr auto path = "/dev/dri/card1";
|
constexpr auto path = "/dev/dri/card1";
|
||||||
|
if(card.init(path)) {
|
||||||
fd.el = open(path, O_RDWR);
|
|
||||||
|
|
||||||
if(fd.el < 0) {
|
|
||||||
BOOST_LOG(error) << "Couldn't open: "sv << path << ": "sv << strerror(errno);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(drmSetClientCap(fd.el, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) {
|
int monitor_index = util::from_view(display_name);
|
||||||
BOOST_LOG(error) << "Couldn't expose some/all drm planes"sv;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
plane_res_t planes = drmModeGetPlaneResources(fd.el);
|
|
||||||
if(!planes) {
|
|
||||||
BOOST_LOG(error) << "Couldn't get drm plane resources"sv;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int monitor_index = 0;
|
|
||||||
int monitor = 0;
|
int monitor = 0;
|
||||||
|
|
||||||
BOOST_LOG(info) << "Found "sv << planes->count_planes << " planes"sv;
|
|
||||||
|
|
||||||
int pitch;
|
int pitch;
|
||||||
for(std::uint32_t x = 0; x < planes->count_planes; ++x) {
|
|
||||||
plane_t plane = drmModeGetPlane(fd.el, planes->planes[x]);
|
|
||||||
|
|
||||||
if(!plane) {
|
auto end = std::end(card);
|
||||||
BOOST_LOG(error) << "Couldn't get drm plane ["sv << x << "]: "sv << strerror(errno);
|
for(auto plane = std::begin(card); plane != end; ++plane) {
|
||||||
|
if(monitor != monitor_index) {
|
||||||
|
++monitor;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!plane->fb_id) {
|
auto fb = card.fb(plane.get());
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
fb_t fb = drmModeGetFB(fd.el, plane->fb_id);
|
|
||||||
if(!fb) {
|
if(!fb) {
|
||||||
BOOST_LOG(error) << "Couldn't get drm fb for plane ["sv << plane->fb_id << "]: "sv << strerror(errno);
|
BOOST_LOG(error) << "Couldn't get drm fb for plane ["sv << plane->fb_id << "]: "sv << strerror(errno);
|
||||||
continue;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
if(monitor++ != monitor_index) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!fb->handle) {
|
if(!fb->handle) {
|
||||||
BOOST_LOG(error)
|
BOOST_LOG(error)
|
||||||
<< "Couldn't get handle for Framebuffer ["sv << plane->fb_id << "]: Possibly not permitted: do [sudo setcap cap_sys_admin+ep sunshine]"sv;
|
<< "Couldn't get handle for DRM Framebuffer ["sv << plane->fb_id << "]: Possibly not permitted: do [sudo setcap cap_sys_admin+ep sunshine]"sv;
|
||||||
continue;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG(info) << "Opened Framebuffer for plane ["sv << plane->fb_id << ']';
|
auto status = drmPrimeHandleToFD(card.fd.el, fb->handle, 0 /* flags */, &fb_fd.el);
|
||||||
|
|
||||||
auto status = drmPrimeHandleToFD(fd.el, fb->handle, 0 /* flags */, &fb_fd.el);
|
|
||||||
if(status || fb_fd.el < 0) {
|
if(status || fb_fd.el < 0) {
|
||||||
BOOST_LOG(error) << "Couldn't get primary file descriptor for Framebuffer ["sv << fb->fb_id << "]: "sv << strerror(errno);
|
BOOST_LOG(error) << "Couldn't get primary file descriptor for Framebuffer ["sv << fb->fb_id << "]: "sv << strerror(errno);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG(info)
|
BOOST_LOG(info) << "Found monitor for DRM screencasting"sv;
|
||||||
<< "x("sv << plane->x << ") y("sv << plane->y << ") crtc_x("sv << plane->crtc_x << ") crtc_y("sv << plane->crtc_y << ')';
|
kms::print(plane.get(), fb.get());
|
||||||
|
|
||||||
BOOST_LOG(info)
|
|
||||||
<< "Resolution: "sv << fb->width << 'x' << fb->height
|
|
||||||
<< ": Pitch: "sv << fb->pitch
|
|
||||||
<< ": bpp: "sv << fb->bpp
|
|
||||||
<< ": depth: "sv << fb->depth;
|
|
||||||
|
|
||||||
std::for_each_n(plane->formats, plane->count_formats, [](auto format) {
|
|
||||||
BOOST_LOG(info) << "Format "sv << util::view(format);
|
|
||||||
});
|
|
||||||
|
|
||||||
width = fb->width;
|
width = fb->width;
|
||||||
height = fb->height;
|
height = fb->height;
|
||||||
pitch = fb->pitch;
|
pitch = fb->pitch;
|
||||||
env_width = width;
|
env_width = width;
|
||||||
env_height = height;
|
env_height = height;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gbm.reset(gbm::create_device(fd.el));
|
if(monitor != monitor_index) {
|
||||||
|
BOOST_LOG(error) << "Couldn't find monitor ["sv << monitor_index << ']';
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gbm.reset(gbm::create_device(card.fd.el));
|
||||||
if(!gbm) {
|
if(!gbm) {
|
||||||
BOOST_LOG(error) << "Couldn't create GBM device: ["sv << util::hex(eglGetError()).to_string_view() << ']';
|
BOOST_LOG(error) << "Couldn't create GBM device: ["sv << util::hex(eglGetError()).to_string_view() << ']';
|
||||||
return -1;
|
return -1;
|
||||||
@@ -218,7 +313,7 @@ public:
|
|||||||
|
|
||||||
std::chrono::nanoseconds delay;
|
std::chrono::nanoseconds delay;
|
||||||
|
|
||||||
egl::file_t fd;
|
card_t card;
|
||||||
egl::file_t fb_fd;
|
egl::file_t fb_fd;
|
||||||
|
|
||||||
gbm::gbm_t gbm;
|
gbm::gbm_t gbm;
|
||||||
@@ -229,20 +324,52 @@ public:
|
|||||||
};
|
};
|
||||||
} // namespace kms
|
} // namespace kms
|
||||||
|
|
||||||
std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, int framerate) {
|
std::shared_ptr<display_t> kms_display(mem_type_e hwdevice_type, const std::string &display_name, int framerate) {
|
||||||
auto disp = std::make_shared<kms::display_t>();
|
auto disp = std::make_shared<kms::display_t>();
|
||||||
|
|
||||||
if(disp->init(display_name, framerate)) {
|
if(disp->init(display_name, framerate)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG(info) << "Opened DRM Display"sv;
|
|
||||||
return disp;
|
return disp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A list of names of displays accepted as display_name
|
// A list of names of displays accepted as display_name
|
||||||
std::vector<std::string> display_names() {
|
std::vector<std::string> kms_display_names() {
|
||||||
return {};
|
if(!gbm::create_device) {
|
||||||
|
BOOST_LOG(warning) << "libgbm not initialized"sv;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> display_names;
|
||||||
|
|
||||||
|
kms::card_t card;
|
||||||
|
if(card.init("/dev/dri/card1")) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
auto end = std::end(card);
|
||||||
|
for(auto plane = std::begin(card); plane != end; ++plane) {
|
||||||
|
auto fb = card.fb(plane.get());
|
||||||
|
if(!fb) {
|
||||||
|
BOOST_LOG(error) << "Couldn't get drm fb for plane ["sv << plane->fb_id << "]: "sv << strerror(errno);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!fb->handle) {
|
||||||
|
BOOST_LOG(error)
|
||||||
|
<< "Couldn't get handle for DRM Framebuffer ["sv << plane->fb_id << "]: Possibly not permitted: do [sudo setcap cap_sys_admin+ep sunshine]"sv;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
kms::print(plane.get(), fb.get());
|
||||||
|
|
||||||
|
display_names.emplace_back(std::to_string(count++));
|
||||||
|
}
|
||||||
|
|
||||||
|
return display_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace platf
|
} // namespace platf
|
||||||
@@ -7,7 +7,10 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "graphics.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
#include "vaapi.h"
|
||||||
|
|
||||||
#include "sunshine/main.h"
|
#include "sunshine/main.h"
|
||||||
#include "sunshine/platform/common.h"
|
#include "sunshine/platform/common.h"
|
||||||
|
|
||||||
@@ -20,6 +23,47 @@
|
|||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
namespace dyn {
|
||||||
|
void *handle(const std::vector<const char *> &libs) {
|
||||||
|
void *handle;
|
||||||
|
|
||||||
|
for(auto lib : libs) {
|
||||||
|
handle = dlopen(lib, RTLD_LAZY | RTLD_LOCAL);
|
||||||
|
if(handle) {
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Couldn't find any of the following libraries: ["sv << libs.front();
|
||||||
|
std::for_each(std::begin(libs) + 1, std::end(libs), [&](auto lib) {
|
||||||
|
ss << ", "sv << lib;
|
||||||
|
});
|
||||||
|
|
||||||
|
ss << ']';
|
||||||
|
|
||||||
|
BOOST_LOG(error) << ss.str();
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &funcs, bool strict) {
|
||||||
|
int err = 0;
|
||||||
|
for(auto &func : funcs) {
|
||||||
|
TUPLE_2D_REF(fn, name, func);
|
||||||
|
|
||||||
|
*fn = SUNSHINE_GNUC_EXTENSION(apiproc) dlsym(handle, name);
|
||||||
|
|
||||||
|
if(!*fn && strict) {
|
||||||
|
BOOST_LOG(error) << "Couldn't find function: "sv << name;
|
||||||
|
|
||||||
|
err = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
} // namespace dyn
|
||||||
namespace platf {
|
namespace platf {
|
||||||
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
|
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
|
||||||
|
|
||||||
@@ -93,46 +137,94 @@ std::string get_mac_address(const std::string_view &address) {
|
|||||||
BOOST_LOG(warning) << "Unable to find MAC address for "sv << address;
|
BOOST_LOG(warning) << "Unable to find MAC address for "sv << address;
|
||||||
return "00:00:00:00:00:00"s;
|
return "00:00:00:00:00:00"s;
|
||||||
}
|
}
|
||||||
} // namespace platf
|
|
||||||
|
|
||||||
namespace dyn {
|
enum class source_e {
|
||||||
void *handle(const std::vector<const char *> &libs) {
|
#ifdef SUNSHINE_BUILD_DRM
|
||||||
void *handle;
|
KMS,
|
||||||
|
#endif
|
||||||
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
|
X11,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
static source_e source;
|
||||||
|
|
||||||
for(auto lib : libs) {
|
#ifdef SUNSHINE_BUILD_DRM
|
||||||
handle = dlopen(lib, RTLD_LAZY | RTLD_LOCAL);
|
std::vector<std::string> kms_display_names();
|
||||||
if(handle) {
|
std::shared_ptr<display_t> kms_display(mem_type_e hwdevice_type, const std::string &display_name, int framerate);
|
||||||
return handle;
|
|
||||||
}
|
bool verify_kms() {
|
||||||
|
return !kms_display_names().empty();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
|
std::vector<std::string> x11_display_names();
|
||||||
|
std::shared_ptr<display_t> x11_display(mem_type_e hwdevice_type, const std::string &display_name, int framerate);
|
||||||
|
|
||||||
|
bool verify_x11() {
|
||||||
|
return !x11_display_names().empty();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::vector<std::string> display_names() {
|
||||||
|
switch(source) {
|
||||||
|
#ifdef SUNSHINE_BUILD_DRM
|
||||||
|
case source_e::KMS:
|
||||||
|
return kms_display_names();
|
||||||
|
#endif
|
||||||
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
|
case source_e::X11:
|
||||||
|
return x11_display_names();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream ss;
|
return {};
|
||||||
ss << "Couldn't find any of the following libraries: ["sv << libs.front();
|
}
|
||||||
std::for_each(std::begin(libs) + 1, std::end(libs), [&](auto lib) {
|
|
||||||
ss << ", "sv << lib;
|
|
||||||
});
|
|
||||||
|
|
||||||
ss << ']';
|
std::shared_ptr<display_t> display(mem_type_e hwdevice_type, const std::string &display_name, int framerate) {
|
||||||
|
switch(source) {
|
||||||
BOOST_LOG(error) << ss.str();
|
#ifdef SUNSHINE_BUILD_DRM
|
||||||
|
case source_e::KMS:
|
||||||
|
return kms_display(hwdevice_type, display_name, framerate);
|
||||||
|
#endif
|
||||||
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
|
case source_e::X11:
|
||||||
|
return x11_display(hwdevice_type, display_name, framerate);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load(void *handle, const std::vector<std::tuple<apiproc *, const char *>> &funcs, bool strict) {
|
std::unique_ptr<deinit_t> init() {
|
||||||
int err = 0;
|
// These are allowed to fail.
|
||||||
for(auto &func : funcs) {
|
gbm::init();
|
||||||
TUPLE_2D_REF(fn, name, func);
|
va::init();
|
||||||
|
|
||||||
*fn = SUNSHINE_GNUC_EXTENSION(apiproc) dlsym(handle, name);
|
#ifdef SUNSHINE_BUILD_DRM
|
||||||
|
if(verify_kms()) {
|
||||||
|
BOOST_LOG(info) << "Using KMS for screencasting"sv;
|
||||||
|
source = source_e::KMS;
|
||||||
|
goto found_source;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef SUNSHINE_BUILD_X11
|
||||||
|
if(verify_x11()) {
|
||||||
|
BOOST_LOG(info) << "Using X11 for screencasting"sv;
|
||||||
|
source = source_e::X11;
|
||||||
|
goto found_source;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// Did not find a source
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
if(!*fn && strict) {
|
// Normally, I would simply use if-else statements to achieve this result,
|
||||||
BOOST_LOG(error) << "Couldn't find function: "sv << name;
|
// but due to the macro's, (*spits on ground*), it would be too messy
|
||||||
|
found_source:
|
||||||
err = -1;
|
if(!gladLoaderLoadEGL(EGL_NO_DISPLAY) || !eglGetPlatformDisplay) {
|
||||||
}
|
BOOST_LOG(warning) << "Couldn't load EGL library"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return std::make_unique<deinit_t>();
|
||||||
}
|
}
|
||||||
} // namespace dyn
|
} // namespace platf
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
#define SUNSHINE_PLATFORM_MISC_H
|
#define SUNSHINE_PLATFORM_MISC_H
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace dyn {
|
namespace dyn {
|
||||||
typedef void (*apiproc)(void);
|
typedef void (*apiproc)(void);
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ exportSurfaceHandle_fn exportSurfaceHandle;
|
|||||||
|
|
||||||
using display_t = util::dyn_safe_ptr_v2<void, VAStatus, &terminate>;
|
using display_t = util::dyn_safe_ptr_v2<void, VAStatus, &terminate>;
|
||||||
|
|
||||||
int init() {
|
int init_main_va() {
|
||||||
static void *handle { nullptr };
|
static void *handle { nullptr };
|
||||||
static bool funcs_loaded = false;
|
static bool funcs_loaded = false;
|
||||||
|
|
||||||
@@ -129,8 +129,8 @@ int init() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_drm() {
|
int init() {
|
||||||
if(init()) {
|
if(init_main_va()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,17 +346,4 @@ std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height) {
|
|||||||
|
|
||||||
return egl;
|
return egl;
|
||||||
}
|
}
|
||||||
} // namespace va
|
} // namespace va
|
||||||
|
|
||||||
namespace platf {
|
|
||||||
std::unique_ptr<deinit_t> init() {
|
|
||||||
gbm::init();
|
|
||||||
va::init_drm();
|
|
||||||
|
|
||||||
if(!gladLoaderLoadEGL(EGL_NO_DISPLAY) || !eglGetPlatformDisplay) {
|
|
||||||
BOOST_LOG(warning) << "Couldn't load EGL library"sv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_unique<deinit_t>();
|
|
||||||
}
|
|
||||||
} // namespace platf
|
|
||||||
@@ -4,5 +4,7 @@
|
|||||||
#include "sunshine/platform/common.h"
|
#include "sunshine/platform/common.h"
|
||||||
namespace va {
|
namespace va {
|
||||||
std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height);
|
std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height);
|
||||||
|
|
||||||
|
int init();
|
||||||
} // namespace va
|
} // namespace va
|
||||||
#endif
|
#endif
|
||||||
@@ -398,7 +398,7 @@ struct x11_attr_t : public display_t {
|
|||||||
x11::InitThreads();
|
x11::InitThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
int init(int framerate) {
|
int init(const std::string &display_name, int framerate) {
|
||||||
if(!xdisplay) {
|
if(!xdisplay) {
|
||||||
BOOST_LOG(error) << "Could not open X11 display"sv;
|
BOOST_LOG(error) << "Could not open X11 display"sv;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -411,8 +411,8 @@ struct x11_attr_t : public display_t {
|
|||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
int streamedMonitor = -1;
|
int streamedMonitor = -1;
|
||||||
if(!config::video.output_name.empty()) {
|
if(!display_name.empty()) {
|
||||||
streamedMonitor = (int)util::from_view(config::video.output_name);
|
streamedMonitor = (int)util::from_view(display_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(streamedMonitor != -1) {
|
if(streamedMonitor != -1) {
|
||||||
@@ -529,7 +529,7 @@ struct x11_attr_t : public display_t {
|
|||||||
|
|
||||||
std::shared_ptr<hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) override {
|
std::shared_ptr<hwdevice_t> make_hwdevice(pix_fmt_e pix_fmt) override {
|
||||||
if(mem_type == mem_type_e::vaapi) {
|
if(mem_type == mem_type_e::vaapi) {
|
||||||
return egl::make_hwdevice(width, height);
|
return va::make_hwdevice(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<hwdevice_t>();
|
return std::make_shared<hwdevice_t>();
|
||||||
@@ -642,8 +642,8 @@ struct shm_attr_t : public x11_attr_t {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init(int framerate) {
|
int init(const std::string &display_name, int framerate) {
|
||||||
if(x11_attr_t::init(framerate)) {
|
if(x11_attr_t::init(display_name, framerate)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,7 +686,7 @@ struct shm_attr_t : public x11_attr_t {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<display_t> display(platf::mem_type_e hwdevice_type, int framerate) {
|
std::shared_ptr<display_t> x11_display(platf::mem_type_e hwdevice_type, const std::string &display_name, int framerate) {
|
||||||
if(hwdevice_type != platf::mem_type_e::system && hwdevice_type != platf::mem_type_e::vaapi && hwdevice_type != platf::mem_type_e::cuda) {
|
if(hwdevice_type != platf::mem_type_e::system && hwdevice_type != platf::mem_type_e::vaapi && hwdevice_type != platf::mem_type_e::cuda) {
|
||||||
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
|
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -701,7 +701,7 @@ std::shared_ptr<display_t> display(platf::mem_type_e hwdevice_type, int framerat
|
|||||||
// Attempt to use shared memory X11 to avoid copying the frame
|
// Attempt to use shared memory X11 to avoid copying the frame
|
||||||
auto shm_disp = std::make_shared<shm_attr_t>(hwdevice_type);
|
auto shm_disp = std::make_shared<shm_attr_t>(hwdevice_type);
|
||||||
|
|
||||||
auto status = shm_disp->init(framerate);
|
auto status = shm_disp->init(display_name, framerate);
|
||||||
if(status > 0) {
|
if(status > 0) {
|
||||||
// x11_attr_t::init() failed, don't bother trying again.
|
// x11_attr_t::init() failed, don't bother trying again.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -713,18 +713,18 @@ std::shared_ptr<display_t> display(platf::mem_type_e hwdevice_type, int framerat
|
|||||||
|
|
||||||
// Fallback
|
// Fallback
|
||||||
auto x11_disp = std::make_shared<x11_attr_t>(hwdevice_type);
|
auto x11_disp = std::make_shared<x11_attr_t>(hwdevice_type);
|
||||||
if(x11_disp->init(framerate)) {
|
if(x11_disp->init(display_name, framerate)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return x11_disp;
|
return x11_disp;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> display_names() {
|
std::vector<std::string> x11_display_names() {
|
||||||
if(xcb::init_shm() || xcb::init() || x11::init() || x11::rr::init() || x11::fix::init()) {
|
if(xcb::init_shm() || xcb::init() || x11::init() || x11::rr::init() || x11::fix::init()) {
|
||||||
BOOST_LOG(error) << "Couldn't init x11 libraries"sv;
|
BOOST_LOG(error) << "Couldn't init x11 libraries"sv;
|
||||||
|
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG(info) << "Detecting connected monitors"sv;
|
BOOST_LOG(info) << "Detecting connected monitors"sv;
|
||||||
|
|||||||
@@ -592,6 +592,14 @@ bool operator!=(std::nullptr_t, const uniq_ptr<T, D> &y) {
|
|||||||
return (bool)y;
|
return (bool)y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class P>
|
||||||
|
using shared_t = std::shared_ptr<typename P::element_type>;
|
||||||
|
|
||||||
|
template<class P, class T>
|
||||||
|
shared_t<P> make_shared(T *pointer) {
|
||||||
|
return shared_t<P>(reinterpret_cast<typename P::pointer>(pointer), typename P::deleter_type());
|
||||||
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class wrap_ptr {
|
class wrap_ptr {
|
||||||
public:
|
public:
|
||||||
|
|||||||
Reference in New Issue
Block a user