Make KMSgrab smooth on Wayland
This commit is contained in:
@@ -171,8 +171,7 @@ public:
|
|||||||
return props(id, DRM_MODE_OBJECT_CONNECTOR);
|
return props(id, DRM_MODE_OBJECT_CONNECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
plane_t
|
plane_t operator[](std::uint32_t index) {
|
||||||
operator[](std::uint32_t index) {
|
|
||||||
return drmModeGetPlane(fd.el, plane_res->planes[index]);
|
return drmModeGetPlane(fd.el, plane_res->planes[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,6 +199,10 @@ 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, fb2_t::pointer fb, crtc_t::pointer crtc) {
|
||||||
if(crtc) {
|
if(crtc) {
|
||||||
BOOST_LOG(debug) << "crtc("sv << crtc->x << ", "sv << crtc->y << ')';
|
BOOST_LOG(debug) << "crtc("sv << crtc->x << ", "sv << crtc->y << ')';
|
||||||
@@ -235,53 +238,6 @@ void print(plane_t::pointer plane, fb2_t::pointer fb, crtc_t::pointer crtc) {
|
|||||||
class display_t : public platf::display_t {
|
class display_t : public platf::display_t {
|
||||||
public:
|
public:
|
||||||
display_t(mem_type_e mem_type) : platf::display_t(), mem_type { mem_type } {}
|
display_t(mem_type_e mem_type) : platf::display_t(), mem_type { mem_type } {}
|
||||||
~display_t() {
|
|
||||||
while(!thread_pool.cancel(loop_id))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem_type_e mem_type;
|
|
||||||
|
|
||||||
std::chrono::nanoseconds delay;
|
|
||||||
|
|
||||||
// Done on a seperate thread to prevent additional latency to capture code
|
|
||||||
// This code detects if the framebuffer has been removed from KMS
|
|
||||||
void task_loop() {
|
|
||||||
capture_e capture = capture_e::reinit;
|
|
||||||
|
|
||||||
std::uint32_t framebuffer_count = 0;
|
|
||||||
|
|
||||||
auto end = std::end(card);
|
|
||||||
for(auto plane = std::begin(card); plane != end; ++plane) {
|
|
||||||
if(++framebuffer_count != framebuffer_index) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
capture = capture_e::error;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto crct = card.crtc(plane->crtc_id);
|
|
||||||
|
|
||||||
bool different =
|
|
||||||
fb->width != img_width ||
|
|
||||||
fb->height != img_height ||
|
|
||||||
fb->pitch != pitch ||
|
|
||||||
crct->x != offset_x ||
|
|
||||||
crct->y != offset_y;
|
|
||||||
|
|
||||||
if(!different) {
|
|
||||||
capture = capture_e::ok;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->status = capture;
|
|
||||||
|
|
||||||
loop_id = thread_pool.pushDelayed(&display_t::task_loop, 2s, this).task_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
int init(const std::string &display_name, int framerate) {
|
int init(const std::string &display_name, int framerate) {
|
||||||
delay = std::chrono::nanoseconds { 1s } / framerate;
|
delay = std::chrono::nanoseconds { 1s } / framerate;
|
||||||
@@ -303,12 +259,8 @@ public:
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t framebuffer_index = 0;
|
|
||||||
|
|
||||||
auto end = std::end(card);
|
auto end = std::end(card);
|
||||||
for(auto plane = std::begin(card); plane != end; ++plane) {
|
for(auto plane = std::begin(card); plane != end; ++plane) {
|
||||||
++framebuffer_index;
|
|
||||||
|
|
||||||
bool cursor = false;
|
bool cursor = false;
|
||||||
|
|
||||||
auto props = card.plane_props(plane->plane_id);
|
auto props = card.plane_props(plane->plane_id);
|
||||||
@@ -345,10 +297,10 @@ public:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fb_fd = card.handleFD(fb->handles[0]);
|
file_t fb_fd = card.handleFD(fb->handles[0]);
|
||||||
if(fb_fd.el < 0) {
|
if(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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG(info) << "Found monitor for DRM screencasting"sv;
|
BOOST_LOG(info) << "Found monitor for DRM screencasting"sv;
|
||||||
@@ -362,9 +314,6 @@ public:
|
|||||||
width = crct->width;
|
width = crct->width;
|
||||||
height = crct->height;
|
height = crct->height;
|
||||||
|
|
||||||
pitch = fb->pitches[0];
|
|
||||||
offset = fb->offsets[0];
|
|
||||||
|
|
||||||
this->env_width = ::platf::kms::env_width;
|
this->env_width = ::platf::kms::env_width;
|
||||||
this->env_height = ::platf::kms::env_height;
|
this->env_height = ::platf::kms::env_height;
|
||||||
|
|
||||||
@@ -373,7 +322,7 @@ public:
|
|||||||
|
|
||||||
this->card = std::move(card);
|
this->card = std::move(card);
|
||||||
|
|
||||||
this->framebuffer_index = framebuffer_index;
|
plane_id = plane->plane_id;
|
||||||
|
|
||||||
goto break_loop;
|
goto break_loop;
|
||||||
}
|
}
|
||||||
@@ -389,30 +338,54 @@ public:
|
|||||||
|
|
||||||
cursor_opt = x11::cursor_t::make();
|
cursor_opt = x11::cursor_t::make();
|
||||||
|
|
||||||
status = capture_e::ok;
|
|
||||||
|
|
||||||
thread_pool.start(1);
|
|
||||||
loop_id = thread_pool.pushDelayed(&display_t::task_loop, 2s, this).task_id;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep track of what framebuffer we're using.
|
inline capture_e refresh(file_t *file) {
|
||||||
std::uint32_t framebuffer_index;
|
plane_t plane = drmModeGetPlane(card.fd.el, plane_id);
|
||||||
|
|
||||||
capture_e status;
|
auto fb = card.fb2(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!fb->handles[0]) {
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(
|
||||||
|
fb->width != img_width ||
|
||||||
|
fb->height != img_height) {
|
||||||
|
return capture_e::reinit;
|
||||||
|
}
|
||||||
|
|
||||||
|
pitch = fb->pitches[0];
|
||||||
|
offset = fb->offsets[0];
|
||||||
|
|
||||||
|
return capture_e::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_type_e mem_type;
|
||||||
|
|
||||||
|
std::chrono::nanoseconds delay;
|
||||||
|
|
||||||
int img_width, img_height;
|
int img_width, img_height;
|
||||||
int pitch;
|
int pitch;
|
||||||
int offset;
|
int offset;
|
||||||
|
int plane_id;
|
||||||
|
|
||||||
card_t card;
|
card_t card;
|
||||||
file_t fb_fd;
|
|
||||||
|
|
||||||
std::optional<x11::cursor_t> cursor_opt;
|
std::optional<x11::cursor_t> cursor_opt;
|
||||||
|
|
||||||
util::TaskPool::task_id_t loop_id;
|
|
||||||
util::ThreadPool thread_pool;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class display_ram_t : public display_t {
|
class display_ram_t : public display_t {
|
||||||
@@ -447,21 +420,6 @@ public:
|
|||||||
|
|
||||||
ctx = std::move(*ctx_opt);
|
ctx = std::move(*ctx_opt);
|
||||||
|
|
||||||
auto rgb_opt = egl::import_source(display.get(),
|
|
||||||
{
|
|
||||||
fb_fd.el,
|
|
||||||
img_width,
|
|
||||||
img_height,
|
|
||||||
offset,
|
|
||||||
pitch,
|
|
||||||
});
|
|
||||||
|
|
||||||
if(!rgb_opt) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rgb = std::move(*rgb_opt);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,6 +466,28 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
|
capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds timeout, bool cursor) {
|
||||||
|
file_t fb_fd;
|
||||||
|
|
||||||
|
auto status = refresh(&fb_fd);
|
||||||
|
if(status != capture_e::ok) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rgb_opt = egl::import_source(display.get(),
|
||||||
|
{
|
||||||
|
fb_fd.el,
|
||||||
|
img_width,
|
||||||
|
img_height,
|
||||||
|
offset,
|
||||||
|
pitch,
|
||||||
|
});
|
||||||
|
|
||||||
|
if(!rgb_opt) {
|
||||||
|
return capture_e::error;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &rgb = *rgb_opt;
|
||||||
|
|
||||||
gl::ctx.BindTexture(GL_TEXTURE_2D, rgb->tex[0]);
|
gl::ctx.BindTexture(GL_TEXTURE_2D, rgb->tex[0]);
|
||||||
gl::ctx.GetTextureSubImage(rgb->tex[0], 0, offset_x, offset_y, 0, width, height, 1, GL_BGRA, GL_UNSIGNED_BYTE, img_out_base->height * img_out_base->row_pitch, img_out_base->data);
|
gl::ctx.GetTextureSubImage(rgb->tex[0], 0, offset_x, offset_y, 0, width, height, 1, GL_BGRA, GL_UNSIGNED_BYTE, img_out_base->height * img_out_base->row_pitch, img_out_base->data);
|
||||||
|
|
||||||
@@ -515,7 +495,7 @@ public:
|
|||||||
cursor_opt->blend(*img_out_base, offset_x, offset_y);
|
cursor_opt->blend(*img_out_base, offset_x, offset_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<img_t> alloc_img() override {
|
std::shared_ptr<img_t> alloc_img() override {
|
||||||
@@ -536,8 +516,6 @@ public:
|
|||||||
gbm::gbm_t gbm;
|
gbm::gbm_t gbm;
|
||||||
egl::display_t display;
|
egl::display_t display;
|
||||||
egl::ctx_t ctx;
|
egl::ctx_t ctx;
|
||||||
|
|
||||||
egl::rgb_t rgb;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class display_vram_t : public display_t {
|
class display_vram_t : public display_t {
|
||||||
@@ -554,25 +532,23 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<img_t> alloc_img() override {
|
std::shared_ptr<img_t> alloc_img() override {
|
||||||
auto img = std::make_shared<egl::img_descriptor_t>();
|
auto img = std::make_shared<kms_vram_img_t>();
|
||||||
|
|
||||||
img->serial = std::numeric_limits<decltype(img->serial)>::max();
|
img->serial = std::numeric_limits<decltype(img->serial)>::max();
|
||||||
img->data = nullptr;
|
img->data = nullptr;
|
||||||
img->pixel_pitch = 4;
|
img->pixel_pitch = 4;
|
||||||
|
|
||||||
img->sequence = 1;
|
img->sequence = 0;
|
||||||
|
|
||||||
img->obj_count = 1;
|
img->obj_count = 1;
|
||||||
img->img_width = img_width;
|
img->img_width = img_width;
|
||||||
img->img_height = img_height;
|
img->img_height = img_height;
|
||||||
img->fds[0] = fb_fd.el;
|
|
||||||
img->offsets[0] = offset;
|
|
||||||
img->strides[0] = pitch;
|
|
||||||
|
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dummy_img(platf::img_t *img) override {
|
int dummy_img(platf::img_t *img) override {
|
||||||
|
snapshot(img, 1s, false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,18 +587,34 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds /* timeout */, bool cursor) {
|
capture_e snapshot(img_t *img_out_base, std::chrono::milliseconds /* timeout */, bool cursor) {
|
||||||
if(!cursor || !cursor_opt) {
|
file_t fb_fd;
|
||||||
img_out_base->data = nullptr;
|
|
||||||
|
auto status = refresh(&fb_fd);
|
||||||
|
if(status != capture_e::ok) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto img = (egl::cursor_t *)img_out_base;
|
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;
|
||||||
|
|
||||||
|
if(!cursor || !cursor_opt) {
|
||||||
|
img_out_base->data = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
return capture_e::ok;
|
||||||
|
}
|
||||||
|
|
||||||
cursor_opt->capture(*img);
|
cursor_opt->capture(*img);
|
||||||
|
|
||||||
img->x -= offset_x;
|
img->x -= offset_x;
|
||||||
img->y -= offset_y;
|
img->y -= offset_y;
|
||||||
|
|
||||||
return status;
|
return capture_e::ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
int init(const std::string &display_name, int framerate) {
|
int init(const std::string &display_name, int framerate) {
|
||||||
@@ -635,8 +627,12 @@ public:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sequence = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::uint64_t sequence;
|
||||||
};
|
};
|
||||||
} // namespace kms
|
} // namespace kms
|
||||||
|
|
||||||
|
|||||||
@@ -417,6 +417,8 @@ public:
|
|||||||
if(descriptor.sequence > sequence) {
|
if(descriptor.sequence > sequence) {
|
||||||
sequence = descriptor.sequence;
|
sequence = descriptor.sequence;
|
||||||
|
|
||||||
|
rgb = egl::rgb_t {};
|
||||||
|
|
||||||
auto rgb_opt = egl::import_source(display.get(),
|
auto rgb_opt = egl::import_source(display.get(),
|
||||||
{
|
{
|
||||||
descriptor.fds[0],
|
descriptor.fds[0],
|
||||||
|
|||||||
Reference in New Issue
Block a user