Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wlgrab fixes #1978

Merged
merged 5 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/platform/linux/graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,36 @@ namespace egl {
return rgb;
}

/**
* @brief Creates a black RGB texture of the specified image size.
* @param img The image to use for texture sizing.
* @return The new RGB texture.
*/
rgb_t
create_blank(platf::img_t &img) {
rgb_t rgb {
EGL_NO_DISPLAY,
EGL_NO_IMAGE,
gl::tex_t::make(1)
};

gl::ctx.BindTexture(GL_TEXTURE_2D, rgb->tex[0]);
gl::ctx.TexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, img.width, img.height);
gl::ctx.BindTexture(GL_TEXTURE_2D, 0);

auto framebuf = gl::frame_buf_t::make(1);
framebuf.bind(&rgb->tex[0], &rgb->tex[0] + 1);

GLenum attachment = GL_COLOR_ATTACHMENT0;
gl::ctx.DrawBuffers(1, &attachment);
const GLuint rgb_black[] = { 0, 0, 0, 0 };
gl::ctx.ClearBufferuiv(GL_COLOR, 0, rgb_black);

gl_drain_errors;

return rgb;
}

std::optional<nv12_t>
import_target(display_t::pointer egl_display, std::array<file_t, nv12_img_t::num_fds> &&fds, const surface_descriptor_t &r8, const surface_descriptor_t &gr88) {
EGLAttrib img_attr_planes[2][17] {
Expand Down
3 changes: 3 additions & 0 deletions src/platform/linux/graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@ namespace egl {
display_t::pointer egl_display,
const surface_descriptor_t &xrgb);

rgb_t
create_blank(platf::img_t &img);

std::optional<nv12_t>
import_target(
display_t::pointer egl_display,
Expand Down
26 changes: 6 additions & 20 deletions src/platform/linux/kmsgrab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -819,17 +819,11 @@ namespace platf {

auto &rgb = *rgb_opt;

gl::ctx.BindTexture(GL_TEXTURE_2D, rgb->tex[0]);

int w, h;
gl::ctx.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
gl::ctx.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
BOOST_LOG(debug) << "width and height: w "sv << w << " h "sv << h;

if (!pull_free_image_cb(img_out)) {
return platf::capture_e::interrupted;
}

gl::ctx.BindTexture(GL_TEXTURE_2D, rgb->tex[0]);
gl::ctx.GetTextureSubImage(rgb->tex[0], 0, img_offset_x, img_offset_y, 0, width, height, 1, GL_BGRA, GL_UNSIGNED_BYTE, img_out->height * img_out->row_pitch, img_out->data);

if (cursor_opt && cursor) {
Expand Down Expand Up @@ -880,6 +874,8 @@ namespace platf {
alloc_img() override {
auto img = std::make_shared<egl::img_descriptor_t>();

img->width = width;
img->height = height;
img->serial = std::numeric_limits<decltype(img->serial)>::max();
img->data = nullptr;
img->pixel_pitch = 4;
Expand All @@ -892,16 +888,8 @@ namespace platf {

int
dummy_img(platf::img_t *img) override {
// TODO: stop cheating and give black image
if (!img) {
return -1;
};
auto pull_dummy_img_callback = [&img](std::shared_ptr<platf::img_t> &img_out) -> bool {
img_out = img->shared_from_this();
return true;
};
std::shared_ptr<platf::img_t> img_out;
return snapshot(pull_dummy_img_callback, img_out, 1s, false) != platf::capture_e::ok;
// Empty images are recognized as dummies by the zero sequence number
return 0;
}

capture_e
Expand Down Expand Up @@ -994,12 +982,10 @@ namespace platf {
return -1;
}

sequence = 0;

return 0;
}

std::uint64_t sequence;
std::uint64_t sequence {};
};

} // namespace kms
Expand Down
6 changes: 5 additions & 1 deletion src/platform/linux/vaapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,11 @@ namespace va {
convert(platf::img_t &img) override {
auto &descriptor = (egl::img_descriptor_t &) img;

if (descriptor.sequence > sequence) {
if (descriptor.sequence == 0) {
// For dummy images, use a blank RGB texture instead of importing a DMA-BUF
rgb = egl::create_blank(img);
}
else if (descriptor.sequence > sequence) {
sequence = descriptor.sequence;

rgb = egl::rgb_t {};
Expand Down
58 changes: 50 additions & 8 deletions src/platform/linux/wayland.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* @file src/platform/linux/wayland.cpp
* @brief todo
*/
#include <poll.h>
#include <wayland-client.h>
#include <wayland-util.h>

Expand Down Expand Up @@ -61,13 +62,52 @@ namespace wl {
wl_display_roundtrip(display_internal.get());
}

/**
* @brief Waits up to the specified timeout to dispatch new events on the wl_display.
* @param timeout The timeout in milliseconds.
* @return true if new events were dispatched or false if the timeout expired.
*/
bool
display_t::dispatch(std::chrono::milliseconds timeout) {
// Check if any events are queued already. If not, flush
// outgoing events, and prepare to wait for readability.
if (wl_display_prepare_read(display_internal.get()) == 0) {
wl_display_flush(display_internal.get());

// Wait for an event to come in
struct pollfd pfd = {};
pfd.fd = wl_display_get_fd(display_internal.get());
pfd.events = POLLIN;
if (poll(&pfd, 1, timeout.count()) == 1 && (pfd.revents & POLLIN)) {
// Read the new event(s)
wl_display_read_events(display_internal.get());
}
else {
// We timed out, so unlock the queue now
wl_display_cancel_read(display_internal.get());
return false;
}
}

// Dispatch any existing or new pending events
wl_display_dispatch_pending(display_internal.get());
return true;
}

wl_registry *
display_t::registry() {
return wl_display_get_registry(display_internal.get());
}

inline monitor_t::monitor_t(wl_output *output):
output { output }, listener {
output { output },
wl_listener {
&CLASS_CALL(monitor_t, wl_geometry),
&CLASS_CALL(monitor_t, wl_mode),
&CLASS_CALL(monitor_t, wl_done),
&CLASS_CALL(monitor_t, wl_scale),
},
xdg_listener {
&CLASS_CALL(monitor_t, xdg_position),
&CLASS_CALL(monitor_t, xdg_size),
&CLASS_CALL(monitor_t, xdg_done),
Expand Down Expand Up @@ -99,21 +139,23 @@ namespace wl {

void
monitor_t::xdg_size(zxdg_output_v1 *, std::int32_t width, std::int32_t height) {
BOOST_LOG(info) << "Logical size: "sv << width << 'x' << height;
}

void
monitor_t::wl_mode(wl_output *wl_output, std::uint32_t flags,
std::int32_t width, std::int32_t height, std::int32_t refresh) {
viewport.width = width;
viewport.height = height;

BOOST_LOG(info) << "Resolution: "sv << width << 'x' << height;
}

void
monitor_t::xdg_done(zxdg_output_v1 *) {
BOOST_LOG(info) << "All info about monitor ["sv << name << "] has been send"sv;
}

void
monitor_t::listen(zxdg_output_manager_v1 *output_manager) {
auto xdg_output = zxdg_output_manager_v1_get_xdg_output(output_manager, output);
zxdg_output_v1_add_listener(xdg_output, &listener, this);
zxdg_output_v1_add_listener(xdg_output, &xdg_listener, this);
wl_output_add_listener(output, &wl_listener, this);
}

interface_t::interface_t() noexcept
Expand All @@ -137,7 +179,7 @@ namespace wl {
BOOST_LOG(info) << "Found interface: "sv << interface << '(' << id << ") version "sv << version;
monitors.emplace_back(
std::make_unique<monitor_t>(
(wl_output *) wl_registry_bind(registry, id, &wl_output_interface, version)));
(wl_output *) wl_registry_bind(registry, id, &wl_output_interface, 2)));
}
else if (!std::strcmp(interface, zxdg_output_manager_v1_interface.name)) {
BOOST_LOG(info) << "Found interface: "sv << interface << '(' << id << ") version "sv << version;
Expand Down
21 changes: 19 additions & 2 deletions src/platform/linux/wayland.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,19 @@ namespace wl {
void
xdg_size(zxdg_output_v1 *, std::int32_t width, std::int32_t height);
void
xdg_done(zxdg_output_v1 *);
xdg_done(zxdg_output_v1 *) {}

void
wl_geometry(wl_output *wl_output, std::int32_t x, std::int32_t y,
std::int32_t physical_width, std::int32_t physical_height, std::int32_t subpixel,
const char *make, const char *model, std::int32_t transform) {}
void
wl_mode(wl_output *wl_output, std::uint32_t flags,
std::int32_t width, std::int32_t height, std::int32_t refresh);
void
wl_done(wl_output *wl_output) {}
void
wl_scale(wl_output *wl_output, std::int32_t factor) {}

void
listen(zxdg_output_manager_v1 *output_manager);
Expand All @@ -130,7 +142,8 @@ namespace wl {

platf::touch_port_t viewport;

zxdg_output_v1_listener listener;
wl_output_listener wl_listener;
zxdg_output_v1_listener xdg_listener;
};

class interface_t {
Expand Down Expand Up @@ -193,6 +206,10 @@ namespace wl {
void
roundtrip();

// Wait up to the timeout to read and dispatch new events
bool
dispatch(std::chrono::milliseconds timeout);

// Get the registry associated with the display
// No need to manually free the registry
wl_registry *
Expand Down
26 changes: 7 additions & 19 deletions src/platform/linux/wlgrab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ namespace wl {
snapshot(const pull_free_image_cb_t &pull_free_image_cb, std::shared_ptr<platf::img_t> &img_out, std::chrono::milliseconds timeout, bool cursor) {
auto to = std::chrono::steady_clock::now() + timeout;

// Dispatch events until we get a new frame or the timeout expires
dmabuf.listen(interface.dmabuf_manager, output, cursor);
do {
display.roundtrip();

if (to < std::chrono::steady_clock::now()) {
auto remaining_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(to - std::chrono::steady_clock::now());
if (remaining_time_ms.count() < 0 || !display.dispatch(remaining_time_ms)) {
return platf::capture_e::timeout;
}
} while (dmabuf.status == dmabuf_t::WAITING);
Expand Down Expand Up @@ -182,12 +182,6 @@ namespace wl {
}

gl::ctx.BindTexture(GL_TEXTURE_2D, (*rgb_opt)->tex[0]);

int w, h;
gl::ctx.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
gl::ctx.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
BOOST_LOG(debug) << "width and height: w "sv << w << " h "sv << h;

gl::ctx.GetTextureSubImage((*rgb_opt)->tex[0], 0, 0, 0, 0, width, height, 1, GL_BGRA, GL_UNSIGNED_BYTE, img_out->height * img_out->row_pitch, img_out->data);
gl::ctx.BindTexture(GL_TEXTURE_2D, 0);

Expand Down Expand Up @@ -313,6 +307,8 @@ namespace wl {
alloc_img() override {
auto img = std::make_shared<egl::img_descriptor_t>();

img->width = width;
img->height = height;
img->sequence = 0;
img->serial = std::numeric_limits<decltype(img->serial)>::max();
img->data = nullptr;
Expand All @@ -334,16 +330,8 @@ namespace wl {

int
dummy_img(platf::img_t *img) override {
// TODO: stop cheating and give black image
if (!img) {
return -1;
};
auto pull_dummy_img_callback = [&img](std::shared_ptr<platf::img_t> &img_out) -> bool {
img_out = img->shared_from_this();
return true;
};
std::shared_ptr<platf::img_t> img_out;
return snapshot(pull_dummy_img_callback, img_out, 1000ms, false) != platf::capture_e::ok;
// Empty images are recognized as dummies by the zero sequence number
return 0;
}

std::uint64_t sequence {};
Expand Down