Merged with master

This commit is contained in:
Loki 2021-09-01 14:22:41 +02:00
commit c7c3ac7c9c
18 changed files with 12357 additions and 222 deletions

View File

@ -150,6 +150,22 @@
that sleeps indefinitely
</div>
</div>
<!--working dir-->
<div class="mb-3">
<label for="appWorkingDir" class="form-label">Working Directory</label>
<input
type="text"
class="form-control monospace"
id="appWorkingDir"
aria-describedby="appWorkingDirHelp"
v-model="editForm['working-dir']"
/>
<div id="appWorkingDirHelp" class="form-text">
The working directory that should be passed to the process.
For example, some applications use the working directory to search for configuration files.
If not set, Sunshine will default to the parent directory of the command
</div>
</div>
<!--buttons-->
<div class="d-flex">
<button @click="showEditForm = false" class="btn btn-secondary m-2">

View File

@ -5,18 +5,9 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sunshine</title>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0"
crossorigin="anonymous"
/>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8"
crossorigin="anonymous"
></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>
<link href="/third_party/bootstrap.min.css" rel="stylesheet" />
<script src="/third_party/bootstrap.bundle.min.js"></script>
<script src="/third_party/vue.js"></script>
</head>
<body></body>

View File

@ -5,18 +5,9 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sunshine</title>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0"
crossorigin="anonymous"
/>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8"
crossorigin="anonymous"
></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>
<link href="/third_party/bootstrap.min.css" rel="stylesheet" />
<script src="/third_party/bootstrap.bundle.min.js"></script>
<script src="/third_party/vue.js"></script>
</head>
<body>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

11965
assets/web/third_party/vue.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@ Package: sunshine
Architecture: amd64
Maintainer: @loki
Priority: optional
Version: 0.10.1
Version: 0.10.2
Depends: libssl1.1, libavdevice58, libboost-thread1.67.0 | libboost-thread1.71.0, libboost-filesystem1.67.0 | libboost-filesystem1.71.0, libboost-log1.67.0 | libboost-log1.71.0, libpulse0, libopus0, libxcb-shm0, libxcb-xfixes0, libxtst6, libevdev2, libdrm2
Description: Gamestream host for Moonlight
EOF

View File

@ -211,6 +211,27 @@ void getWelcomePage(resp_https_t response, req_https_t request) {
response->write(header + content);
}
void getBootstrapCss(resp_https_t response, req_https_t request) {
print_req(request);
std::string content = read_file(WEB_DIR "third_party/bootstrap.min.css");
response->write(content);
}
void getBootstrapJs(resp_https_t response, req_https_t request) {
print_req(request);
std::string content = read_file(WEB_DIR "third_party/bootstrap.bundle.min.js");
response->write(content);
}
void getVueJs(resp_https_t response, req_https_t request) {
print_req(request);
std::string content = read_file(WEB_DIR "third_party/vue.js");
response->write(content);
}
void getApps(resp_https_t response, req_https_t request) {
if(!authenticate(response, request)) return;
@ -490,24 +511,27 @@ void start() {
ctx->use_certificate_chain_file(config::nvhttp.cert);
ctx->use_private_key_file(config::nvhttp.pkey, boost::asio::ssl::context::pem);
https_server_t server { ctx, 0 };
server.default_resource = not_found;
server.resource["^/$"]["GET"] = getIndexPage;
server.resource["^/pin$"]["GET"] = getPinPage;
server.resource["^/apps$"]["GET"] = getAppsPage;
server.resource["^/clients$"]["GET"] = getClientsPage;
server.resource["^/config$"]["GET"] = getConfigPage;
server.resource["^/password$"]["GET"] = getPasswordPage;
server.resource["^/welcome$"]["GET"] = getWelcomePage;
server.resource["^/api/pin"]["POST"] = savePin;
server.resource["^/api/apps$"]["GET"] = getApps;
server.resource["^/api/apps$"]["POST"] = saveApp;
server.resource["^/api/config$"]["GET"] = getConfig;
server.resource["^/api/config$"]["POST"] = saveConfig;
server.resource["^/api/password$"]["POST"] = savePassword;
server.resource["^/api/apps/([0-9]+)$"]["DELETE"] = deleteApp;
server.config.reuse_address = true;
server.config.address = "0.0.0.0"s;
server.config.port = port_https;
server.default_resource = not_found;
server.resource["^/$"]["GET"] = getIndexPage;
server.resource["^/pin$"]["GET"] = getPinPage;
server.resource["^/apps$"]["GET"] = getAppsPage;
server.resource["^/clients$"]["GET"] = getClientsPage;
server.resource["^/config$"]["GET"] = getConfigPage;
server.resource["^/password$"]["GET"] = getPasswordPage;
server.resource["^/welcome$"]["GET"] = getWelcomePage;
server.resource["^/api/pin"]["POST"] = savePin;
server.resource["^/api/apps$"]["GET"] = getApps;
server.resource["^/api/apps$"]["POST"] = saveApp;
server.resource["^/api/config$"]["GET"] = getConfig;
server.resource["^/api/config$"]["POST"] = saveConfig;
server.resource["^/api/password$"]["POST"] = savePassword;
server.resource["^/api/apps/([0-9]+)$"]["DELETE"] = deleteApp;
server.resource["^/third_party/bootstrap.min.css$"]["GET"] = getBootstrapCss;
server.resource["^/third_party/bootstrap.bundle.min.js$"]["GET"] = getBootstrapJs;
server.resource["^/third_party/vue.js$"]["GET"] = getVueJs;
server.config.reuse_address = true;
server.config.address = "0.0.0.0"s;
server.config.port = port_https;
try {
server.bind();

View File

@ -9,12 +9,13 @@
// They aren't likely to change any time soon.
#define fourcc_code(a, b, c, d) ((std::uint32_t)(a) | ((std::uint32_t)(b) << 8) | \
((std::uint32_t)(c) << 16) | ((std::uint32_t)(d) << 24))
#define fourcc_mod_code(vendor, val) ((((uint64_t)vendor) << 56) | ((val)&0x00ffffffffffffffULL))
#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4') /* [31:0] A:R:G:B 8:8:8:8 little endian */
#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */
#define DRM_FORMAT_XBGR8888 fourcc_code('X', 'B', '2', '4') /* [31:0] x:B:G:R 8:8:8:8 little endian */
#define DRM_FORMAT_MOD_INVALID fourcc_mod_code(0, ((1ULL << 56) - 1))
#define SUNSHINE_SHADERS_DIR SUNSHINE_ASSETS_DIR "/shaders/opengl"
@ -278,11 +279,28 @@ int init() {
} // namespace gbm
namespace egl {
constexpr auto EGL_LINUX_DMA_BUF_EXT = 0x3270;
constexpr auto EGL_LINUX_DRM_FOURCC_EXT = 0x3271;
constexpr auto EGL_DMA_BUF_PLANE0_FD_EXT = 0x3272;
constexpr auto EGL_DMA_BUF_PLANE0_OFFSET_EXT = 0x3273;
constexpr auto EGL_DMA_BUF_PLANE0_PITCH_EXT = 0x3274;
constexpr auto EGL_LINUX_DMA_BUF_EXT = 0x3270;
constexpr auto EGL_LINUX_DRM_FOURCC_EXT = 0x3271;
constexpr auto EGL_DMA_BUF_PLANE0_FD_EXT = 0x3272;
constexpr auto EGL_DMA_BUF_PLANE0_OFFSET_EXT = 0x3273;
constexpr auto EGL_DMA_BUF_PLANE0_PITCH_EXT = 0x3274;
constexpr auto EGL_DMA_BUF_PLANE1_FD_EXT = 0x3275;
constexpr auto EGL_DMA_BUF_PLANE1_OFFSET_EXT = 0x3276;
constexpr auto EGL_DMA_BUF_PLANE1_PITCH_EXT = 0x3277;
constexpr auto EGL_DMA_BUF_PLANE2_FD_EXT = 0x3278;
constexpr auto EGL_DMA_BUF_PLANE2_OFFSET_EXT = 0x3279;
constexpr auto EGL_DMA_BUF_PLANE2_PITCH_EXT = 0x327A;
constexpr auto EGL_DMA_BUF_PLANE3_FD_EXT = 0x3440;
constexpr auto EGL_DMA_BUF_PLANE3_OFFSET_EXT = 0x3441;
constexpr auto EGL_DMA_BUF_PLANE3_PITCH_EXT = 0x3442;
constexpr auto EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT = 0x3443;
constexpr auto EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT = 0x3444;
constexpr auto EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT = 0x3445;
constexpr auto EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT = 0x3446;
constexpr auto EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT = 0x3447;
constexpr auto EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT = 0x3448;
constexpr auto EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT = 0x3449;
constexpr auto EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT = 0x344A;
bool fail() {
return eglGetError() != EGL_SUCCESS;
@ -329,7 +347,6 @@ display_t make_display(util::Either<gbm::gbm_t::pointer, wl_display *> native_di
"EGL_KHR_create_context",
"EGL_KHR_surfaceless_context",
"EGL_EXT_image_dma_buf_import",
// "EGL_KHR_image_pixmap"
};
for(auto ext : extensions) {
@ -389,22 +406,87 @@ std::optional<ctx_t> make_ctx(display_t::pointer display) {
return ctx;
}
std::optional<rgb_t> import_source(display_t::pointer egl_display, const surface_descriptor_t &xrgb) {
gl_drain_errors;
EGLAttrib img_attr_planes[13] {
EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_XRGB8888,
EGL_WIDTH, xrgb.width,
EGL_HEIGHT, xrgb.height,
EGL_DMA_BUF_PLANE0_FD_EXT, xrgb.fd,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, xrgb.offset,
EGL_DMA_BUF_PLANE0_PITCH_EXT, xrgb.pitch,
EGL_NONE
};
struct plane_attr_t {
EGLAttrib fd;
EGLAttrib offset;
EGLAttrib pitch;
EGLAttrib lo;
EGLAttrib hi;
};
inline plane_attr_t get_plane(std::uint32_t plane_indice) {
switch(plane_indice) {
case 0:
return {
EGL_DMA_BUF_PLANE0_FD_EXT,
EGL_DMA_BUF_PLANE0_OFFSET_EXT,
EGL_DMA_BUF_PLANE0_PITCH_EXT,
EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
};
case 1:
return {
EGL_DMA_BUF_PLANE1_FD_EXT,
EGL_DMA_BUF_PLANE1_OFFSET_EXT,
EGL_DMA_BUF_PLANE1_PITCH_EXT,
EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
};
case 2:
return {
EGL_DMA_BUF_PLANE2_FD_EXT,
EGL_DMA_BUF_PLANE2_OFFSET_EXT,
EGL_DMA_BUF_PLANE2_PITCH_EXT,
EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
};
case 3:
return {
EGL_DMA_BUF_PLANE3_FD_EXT,
EGL_DMA_BUF_PLANE3_OFFSET_EXT,
EGL_DMA_BUF_PLANE3_PITCH_EXT,
EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT,
};
}
// Avoid warning
return {};
}
std::optional<rgb_t> import_source(display_t::pointer egl_display, const surface_descriptor_t &xrgb) {
EGLAttrib attribs[47];
int atti = 0;
attribs[atti++] = EGL_WIDTH;
attribs[atti++] = xrgb.width;
attribs[atti++] = EGL_HEIGHT;
attribs[atti++] = xrgb.height;
attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
attribs[atti++] = xrgb.fourcc;
for(auto x = 0; x < xrgb.obj_count; ++x) {
auto plane_attr = get_plane(xrgb.plane_indices[x]);
attribs[atti++] = plane_attr.fd;
attribs[atti++] = xrgb.fds[x];
attribs[atti++] = plane_attr.offset;
attribs[atti++] = xrgb.offsets[x];
attribs[atti++] = plane_attr.pitch;
attribs[atti++] = xrgb.pitches[x];
if(xrgb.modifier && xrgb.modifier != DRM_FORMAT_MOD_INVALID) {
attribs[atti++] = plane_attr.lo;
attribs[atti++] = xrgb.modifier & 0xFFFFFFFF;
attribs[atti++] = plane_attr.hi;
attribs[atti++] = xrgb.modifier >> 32;
}
}
attribs[atti++] = EGL_NONE;
rgb_t rgb {
egl_display,
eglCreateImage(egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, img_attr_planes),
eglCreateImage(egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, attribs),
gl::tex_t::make(1)
};
@ -429,17 +511,17 @@ std::optional<nv12_t> import_target(display_t::pointer egl_display, std::array<f
{ EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_R8,
EGL_WIDTH, r8.width,
EGL_HEIGHT, r8.height,
EGL_DMA_BUF_PLANE0_FD_EXT, r8.fd,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, r8.offset,
EGL_DMA_BUF_PLANE0_PITCH_EXT, r8.pitch,
EGL_DMA_BUF_PLANE0_FD_EXT, r8.fds[0],
EGL_DMA_BUF_PLANE0_OFFSET_EXT, r8.offsets[0],
EGL_DMA_BUF_PLANE0_PITCH_EXT, r8.pitches[0],
EGL_NONE },
{ EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_GR88,
EGL_WIDTH, gr88.width,
EGL_HEIGHT, gr88.height,
EGL_DMA_BUF_PLANE0_FD_EXT, r8.fd,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, gr88.offset,
EGL_DMA_BUF_PLANE0_PITCH_EXT, gr88.pitch,
EGL_DMA_BUF_PLANE0_FD_EXT, r8.fds[0],
EGL_DMA_BUF_PLANE0_OFFSET_EXT, gr88.offsets[0],
EGL_DMA_BUF_PLANE0_PITCH_EXT, gr88.pitches[0],
EGL_NONE },
};
@ -728,4 +810,4 @@ int sws_t::convert(nv12_t &nv12) {
void free_frame(AVFrame *frame) {
av_frame_free(&frame);
}
}

View File

@ -213,12 +213,16 @@ KITTY_USING_MOVE_T(ctx_t, (std::tuple<display_t::pointer, EGLContext>), , {
});
struct surface_descriptor_t {
int fd;
int obj_count;
int width;
int height;
int offset;
int pitch;
int fds[4];
std::uint32_t fourcc;
std::uint64_t modifier;
std::uint32_t pitches[4];
std::uint32_t offsets[4];
std::uint32_t plane_indices[4];
};
display_t make_display(util::Either<gbm::gbm_t::pointer, wl_display *> native_display);
@ -245,14 +249,19 @@ public:
// Allow cursor and the underlying image to be kept together
class img_descriptor_t : public cursor_t {
public:
std::uint32_t format;
std::uint32_t img_width, img_height;
std::uint32_t obj_count;
std::uint32_t strides[4];
// std::uint32_t sizes[4];
std::int32_t fds[4];
std::uint32_t offsets[4];
// std::uint32_t plane_indices[4];
~img_descriptor_t() {
reset();
}
void reset() {
std::for_each_n(sd.fds, sd.obj_count, [](int fd) {
close(fd);
});
sd.obj_count = 0;
}
surface_descriptor_t sd;
// Increment sequence when new rgb_t needs to be created
std::uint64_t sequence;
@ -295,4 +304,4 @@ public:
bool fail();
} // namespace egl
#endif
#endif

View File

@ -24,12 +24,56 @@ namespace fs = std::filesystem;
namespace platf {
namespace kms {
class wrapper_fb {
public:
wrapper_fb(drmModeFB *fb)
: fb { fb }, fb_id { fb->fb_id }, width { fb->width }, height { fb->height } {
pixel_format = DRM_FORMAT_XRGB8888;
modifier = DRM_FORMAT_MOD_INVALID;
std::fill_n(handles, 4, 0);
std::fill_n(pitches, 4, 0);
std::fill_n(offsets, 4, 0);
handles[0] = fb->handle;
pitches[0] = fb->pitch;
}
wrapper_fb(drmModeFB2 *fb2)
: fb2 { fb2 }, fb_id { fb2->fb_id }, width { fb2->width }, height { fb2->height } {
pixel_format = fb2->pixel_format;
modifier = fb2->modifier;
memcpy(handles, fb2->handles, sizeof(handles));
memcpy(pitches, fb2->pitches, sizeof(pitches));
memcpy(offsets, fb2->offsets, sizeof(offsets));
}
~wrapper_fb() {
if(fb) {
drmModeFreeFB(fb);
}
else if(fb2) {
drmModeFreeFB2(fb2);
}
}
drmModeFB *fb = nullptr;
drmModeFB2 *fb2 = nullptr;
uint32_t fb_id;
uint32_t width;
uint32_t height;
uint32_t pixel_format;
uint64_t modifier;
uint32_t handles[4];
uint32_t pitches[4];
uint32_t offsets[4];
};
using plane_res_t = util::safe_ptr<drmModePlaneRes, drmModeFreePlaneResources>;
using encoder_t = util::safe_ptr<drmModeEncoder, drmModeFreeEncoder>;
using res_t = util::safe_ptr<drmModeRes, drmModeFreeResources>;
using plane_t = util::safe_ptr<drmModePlane, drmModeFreePlane>;
using fb_t = util::safe_ptr<drmModeFB, drmModeFreeFB>;
using fb2_t = util::safe_ptr<drmModeFB2, drmModeFreeFB2>;
using fb_t = std::unique_ptr<wrapper_fb>;
using crtc_t = util::safe_ptr<drmModeCrtc, drmModeFreeCrtc>;
using obj_prop_t = util::safe_ptr<drmModeObjectProperties, drmModeFreeObjectProperties>;
using prop_t = util::safe_ptr<drmModePropertyRes, drmModeFreeProperty>;
@ -182,11 +226,11 @@ public:
}
fb_t fb(plane_t::pointer plane) {
return drmModeGetFB(fd.el, plane->fb_id);
}
fb2_t fb2(plane_t::pointer plane) {
return drmModeGetFB2(fd.el, plane->fb_id);
auto fb = drmModeGetFB2(fd.el, plane->fb_id);
if(fb) {
return std::make_unique<wrapper_fb>(fb);
}
return std::make_unique<wrapper_fb>(drmModeGetFB(fd.el, plane->fb_id));
}
crtc_t crtc(std::uint32_t id) {
@ -332,11 +376,7 @@ struct kms_img_t : public img_t {
}
};
struct kms_vram_img_t : public egl::img_descriptor_t {
file_t fb_fd;
};
void print(plane_t::pointer plane, fb2_t::pointer fb, crtc_t::pointer crtc) {
void print(plane_t::pointer plane, fb_t::pointer fb, crtc_t::pointer crtc) {
if(crtc) {
BOOST_LOG(debug) << "crtc("sv << crtc->x << ", "sv << crtc->y << ')';
BOOST_LOG(debug) << "crtc("sv << crtc->width << ", "sv << crtc->height << ')';
@ -403,7 +443,7 @@ public:
continue;
}
auto fb = card.fb2(plane.get());
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);
return -1;
@ -415,10 +455,16 @@ public:
return -1;
}
file_t fb_fd = card.handleFD(fb->handles[0]);
if(fb_fd.el < 0) {
BOOST_LOG(error) << "Couldn't get primary file descriptor for Framebuffer ["sv << fb->fb_id << "]: "sv << strerror(errno);
return -1;
for(int i = 0; i < 4; ++i) {
if(!fb->handles[i]) {
break;
}
auto fb_fd = card.handleFD(fb->handles[i]);
if(fb_fd.el < 0) {
BOOST_LOG(error) << "Couldn't get primary file descriptor for Framebuffer ["sv << fb->fb_id << "]: "sv << strerror(errno);
continue;
}
}
BOOST_LOG(info) << "Found monitor for DRM screencasting"sv;
@ -435,6 +481,8 @@ public:
return -1;
}
//TODO: surf_sd = fb->to_sd();
auto crct = card.crtc(plane->crtc_id);
kms::print(plane.get(), fb.get(), crct.get());
@ -486,10 +534,10 @@ public:
return 0;
}
inline capture_e refresh(file_t *file) {
inline capture_e refresh(file_t *file, egl::surface_descriptor_t *sd) {
plane_t plane = drmModeGetPlane(card.fd.el, plane_id);
auto fb = card.fb2(plane.get());
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);
return capture_e::error;
@ -501,20 +549,43 @@ public:
return capture_e::error;
}
*file = card.handleFD(fb->handles[0]);
if(file->el < 0) {
BOOST_LOG(error) << "Couldn't get primary file descriptor for Framebuffer ["sv << fb->fb_id << "]: "sv << strerror(errno);
return capture_e::error;
auto obj_count = 4;
int x = 0;
for(int y = 0; y < 4; ++y) {
if(!fb->handles[y]) {
// It's not clear wheter there could still be valid handles left.
// So, continue anyway.
// TODO: Is this redundent?
--obj_count;
continue;
}
file[x] = card.handleFD(fb->handles[x]);
if(file[x].el < 0) {
BOOST_LOG(error) << "Couldn't get primary file descriptor for Framebuffer ["sv << fb->fb_id << "]: "sv << strerror(errno);
return capture_e::error;
}
sd->fds[x] = file[x].el;
sd->offsets[x] = fb->offsets[y];
sd->pitches[x] = fb->pitches[y];
sd->plane_indices[x] = y;
}
sd->width = fb->width;
sd->height = fb->height;
sd->modifier = fb->modifier;
sd->fourcc = fb->pixel_format;
sd->obj_count = obj_count;
if(
fb->width != img_width ||
fb->height != img_height) {
return capture_e::reinit;
}
pitch = fb->pitches[0];
offset = fb->offsets[0];
++x;
return capture_e::ok;
}
@ -526,8 +597,6 @@ public:
int img_width, img_height;
int img_offset_x, img_offset_y;
int pitch;
int offset;
int plane_id;
card_t card;
@ -613,21 +682,16 @@ public:
}
capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
file_t fb_fd;
file_t fb_fd[4];
auto status = refresh(&fb_fd);
egl::surface_descriptor_t sd;
auto status = refresh(fb_fd, &sd);
if(status != capture_e::ok) {
return status;
}
auto rgb_opt = egl::import_source(display.get(),
{
fb_fd.el,
img_width,
img_height,
offset,
pitch,
});
auto rgb_opt = egl::import_source(display.get(), sd);
if(!rgb_opt) {
return capture_e::error;
@ -679,24 +743,20 @@ public:
}
std::shared_ptr<img_t> alloc_img() override {
auto img = std::make_shared<kms_vram_img_t>();
auto img = std::make_shared<egl::img_descriptor_t>();
img->serial = std::numeric_limits<decltype(img->serial)>::max();
img->data = nullptr;
img->pixel_pitch = 4;
img->sequence = 0;
img->obj_count = 1;
img->img_width = img_width;
img->img_height = img_height;
img->sequence = 0;
img->sd.obj_count = 0;
return img;
}
int dummy_img(platf::img_t *img) override {
snapshot(img, 1s, false);
return 0;
return snapshot(img, 1s, false) != capture_e::ok;
}
capture_e capture(snapshot_cb_t &&snapshot_cb, std::shared_ptr<img_t> img, bool *cursor) {
@ -734,25 +794,24 @@ public:
}
capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds /* timeout */, bool cursor) {
file_t fb_fd;
file_t fb_fd[4];
auto status = refresh(&fb_fd);
auto img = (egl::img_descriptor_t *)img_out_base;
img->reset();
auto status = refresh(fb_fd, &img->sd);
if(status != capture_e::ok) {
return status;
}
auto img = (kms_vram_img_t *)img_out_base;
img->fb_fd = std::move(fb_fd);
img->sequence = ++sequence;
img->fds[0] = img->fb_fd.el;
img->offsets[0] = offset;
img->strides[0] = pitch;
img->sequence = ++sequence;
if(!cursor || !cursor_opt) {
img_out_base->data = nullptr;
for(auto x = 0; x < img->sd.obj_count; ++x) {
fb_fd[x].release();
}
return capture_e::ok;
}
@ -761,6 +820,9 @@ public:
img->x -= offset_x;
img->y -= offset_y;
for(auto x = 0; x < img->sd.obj_count; ++x) {
fb_fd[x].release();
}
return capture_e::ok;
}
@ -897,7 +959,7 @@ std::vector<std::string> kms_display_names() {
auto end = std::end(card);
for(auto plane = std::begin(card); plane != end; ++plane) {
auto fb = card.fb2(plane.get());
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;
@ -970,4 +1032,4 @@ std::vector<std::string> kms_display_names() {
return display_names;
}
} // namespace platf
} // namespace platf

View File

@ -350,20 +350,22 @@ public:
auto nv12_opt = egl::import_target(
display.get(),
std::move(fds),
{
prime.objects[prime.layers[0].object_index[0]].fd,
{ 1,
(int)prime.width,
(int)prime.height,
(int)prime.layers[0].offset[0],
(int)prime.layers[0].pitch[0],
},
{
prime.objects[prime.layers[0].object_index[1]].fd,
{ prime.objects[prime.layers[0].object_index[0]].fd, -1, -1, -1 },
0,
0,
{ prime.layers[0].pitch[0] },
{ prime.layers[0].offset[0] } },
{ 1,
(int)prime.width / 2,
(int)prime.height / 2,
(int)prime.layers[0].offset[1],
(int)prime.layers[0].pitch[1],
});
{ prime.objects[prime.layers[0].object_index[1]].fd, -1, -1, -1 },
0,
0,
{ prime.layers[0].pitch[1] },
{ prime.layers[0].offset[1] } });
if(!nv12_opt) {
return -1;
@ -419,14 +421,7 @@ public:
rgb = egl::rgb_t {};
auto rgb_opt = egl::import_source(display.get(),
{
descriptor.fds[0],
(int)descriptor.img_width,
(int)descriptor.img_height,
(int)descriptor.offsets[0],
(int)descriptor.strides[0],
});
auto rgb_opt = egl::import_source(display.get(), descriptor.sd);
if(!rgb_opt) {
return -1;
@ -657,4 +652,4 @@ std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height, int offs
std::shared_ptr<platf::hwdevice_t> make_hwdevice(int width, int height, bool vram) {
return make_hwdevice(width, height, 0, 0, vram);
}
} // namespace va
} // namespace va

View File

@ -164,10 +164,15 @@ void dmabuf_t::frame(
std::uint32_t obj_count) {
auto next_frame = get_next_frame();
next_frame->format = format;
next_frame->width = width;
next_frame->height = height;
next_frame->obj_count = obj_count;
next_frame->sd.fourcc = format;
next_frame->sd.width = width;
next_frame->sd.height = height;
next_frame->sd.modifier = (((std::uint64_t)high) << 32) | low;
next_frame->obj_count = obj_count;
std::fill_n(next_frame->sd.fds + obj_count, 4 - obj_count, -1);
std::fill_n(next_frame->sd.pitches + obj_count, 4 - obj_count, 0);
std::fill_n(next_frame->sd.offsets + obj_count, 4 - obj_count, 0);
}
void dmabuf_t::object(
@ -180,11 +185,10 @@ void dmabuf_t::object(
std::uint32_t plane_index) {
auto next_frame = get_next_frame();
next_frame->fds[index] = fd;
next_frame->sizes[index] = size;
next_frame->strides[index] = stride;
next_frame->offsets[index] = offset;
next_frame->plane_indices[index] = plane_index;
next_frame->sd.fds[index] = fd;
next_frame->sd.pitches[index] = stride;
next_frame->sd.offsets[index] = offset;
next_frame->sd.plane_indices[index] = plane_index;
}
void dmabuf_t::ready(
@ -213,7 +217,7 @@ void dmabuf_t::cancel(
void frame_t::destroy() {
for(auto x = 0; x < obj_count; ++x) {
close(fds[x]);
close(sd.fds[x]);
}
obj_count = 0;

View File

@ -21,14 +21,9 @@ using display_internal_t = util::safe_ptr<wl_display, wl_display_disconnect>;
class frame_t {
public:
std::uint32_t format;
std::uint32_t width, height;
egl::surface_descriptor_t sd;
std::uint32_t obj_count;
std::uint32_t strides[4];
std::uint32_t sizes[4];
std::int32_t fds[4];
std::uint32_t offsets[4];
std::uint32_t plane_indices[4];
void destroy();
};

View File

@ -16,21 +16,6 @@ struct img_t : public platf::img_t {
}
};
class frame_descriptor_t : public egl::img_descriptor_t {
public:
~frame_descriptor_t() {
reset();
}
void reset() {
std::for_each_n(fds, obj_count, [](int fd) {
close(fd);
});
obj_count = 0;
}
};
class wlr_t : public platf::display_t {
public:
int init(platf::mem_type_e hwdevice_type, const std::string &display_name, int framerate) {
@ -107,8 +92,8 @@ public:
if(
dmabuf.status == dmabuf_t::REINIT ||
current_frame->width != width ||
current_frame->height != height) {
current_frame->sd.width != width ||
current_frame->sd.height != height) {
return platf::capture_e::reinit;
}
@ -170,14 +155,7 @@ public:
auto current_frame = dmabuf.current_frame;
auto rgb_opt = egl::import_source(egl_display.get(),
{
current_frame->fds[0],
(int)current_frame->width,
(int)current_frame->height,
(int)current_frame->offsets[0],
(int)current_frame->strides[0],
});
auto rgb_opt = egl::import_source(egl_display.get(), current_frame->sd);
if(!rgb_opt) {
return platf::capture_e::reinit;
@ -274,7 +252,7 @@ public:
return status;
}
auto img = (frame_descriptor_t *)img_out_base;
auto img = (egl::img_descriptor_t *)img_out_base;
img->reset();
auto current_frame = dmabuf.current_frame;
@ -282,14 +260,8 @@ public:
++sequence;
img->sequence = sequence;
img->obj_count = 1;
img->img_width = current_frame->width;
img->img_height = current_frame->height;
img->obj_count = current_frame->obj_count;
std::copy_n(std::begin(current_frame->fds), current_frame->obj_count, img->fds);
std::copy_n(std::begin(current_frame->offsets), current_frame->obj_count, img->offsets);
std::copy_n(std::begin(current_frame->strides), current_frame->obj_count, img->strides);
img->sd = current_frame->sd;
img->sd.obj_count = current_frame->obj_count;
// Prevent dmabuf from closing the file descriptors.
current_frame->obj_count = 0;
@ -298,13 +270,11 @@ public:
}
std::shared_ptr<platf::img_t> alloc_img() override {
auto img = std::make_shared<frame_descriptor_t>();
auto img = std::make_shared<egl::img_descriptor_t>();
img->img_width = width;
img->img_height = height;
img->sequence = 0;
img->serial = std::numeric_limits<decltype(img->serial)>::max();
img->data = nullptr;
img->sequence = 0;
img->serial = std::numeric_limits<decltype(img->serial)>::max();
img->data = nullptr;
return img;
}

View File

@ -11,6 +11,7 @@
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/filesystem.hpp>
#include "main.h"
#include "utility.h"
@ -109,14 +110,17 @@ int proc_t::execute(int app_id) {
if(proc.cmd.empty()) {
BOOST_LOG(debug) << "Executing [Desktop]"sv;
placebo = true;
}
else if(proc.output.empty() || proc.output == "null"sv) {
BOOST_LOG(info) << "Executing: ["sv << proc.cmd << ']';
_process = bp::child(_process_handle, proc.cmd, _env, bp::std_out > bp::null, bp::std_err > bp::null, ec);
}
else {
BOOST_LOG(info) << "Executing: ["sv << proc.cmd << ']';
_process = bp::child(_process_handle, proc.cmd, _env, bp::std_out > _pipe.get(), bp::std_err > _pipe.get(), ec);
} else {
boost::filesystem::path working_dir = proc.working_dir.empty() ?
boost::filesystem::path(proc.cmd).parent_path() : boost::filesystem::path(proc.working_dir);
if(proc.output.empty() || proc.output == "null"sv) {
BOOST_LOG(info) << "Executing: ["sv << proc.cmd << ']';
_process = bp::child(_process_handle, proc.cmd, _env, bp::start_dir(working_dir), bp::std_out > bp::null, bp::std_err > bp::null, ec);
}
else {
BOOST_LOG(info) << "Executing: ["sv << proc.cmd << ']';
_process = bp::child(_process_handle, proc.cmd, _env, bp::start_dir(working_dir), bp::std_out > _pipe.get(), bp::std_err > _pipe.get(), ec);
}
}
if(ec) {
@ -275,6 +279,7 @@ std::optional<proc::proc_t> parse(const std::string &file_name) {
auto output = app_node.get_optional<std::string>("output"s);
auto name = parse_env_val(this_env, app_node.get<std::string>("name"s));
auto cmd = app_node.get_optional<std::string>("cmd"s);
auto working_dir = app_node.get_optional<std::string>("working-dir"s);
std::vector<proc::cmd_t> prep_cmds;
if(prep_nodes_opt) {
@ -312,6 +317,10 @@ std::optional<proc::proc_t> parse(const std::string &file_name) {
ctx.cmd = parse_env_val(this_env, *cmd);
}
if(working_dir) {
ctx.working_dir = parse_env_val(this_env, *working_dir);
}
ctx.name = std::move(name);
ctx.prep_cmds = std::move(prep_cmds);
ctx.detached = std::move(detached);

View File

@ -34,6 +34,7 @@ struct cmd_t {
* cmd -- Runs indefinitely until:
* No session is running and a different set of commands it to be executed
* Command exits
* working_dir -- the process working directory. This is required for some games to run properly.
* cmd_output --
* empty -- The output of the commands are appended to the output of sunshine
* "null" -- The output of the commands are discarded
@ -52,6 +53,7 @@ struct ctx_t {
std::string name;
std::string cmd;
std::string working_dir;
std::string output;
};

View File

@ -46,6 +46,12 @@ struct argument_type<T(U)> { typedef U type; };
element_type *operator->() { return &el; } \
const element_type *operator->() const { return &el; } \
\
inline element_type release() { \
element_type val = std::move(el); \
el = element_type { init_val }; \
return val; \
} \
\
~move_t() z \
\
element_type el; \