Test for capability of modifiers when importing framebuffer to openGL

This commit is contained in:
loki-47-6F-64 2021-09-02 20:38:45 +02:00
commit 276aa23a61

View file

@ -28,9 +28,8 @@ 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;
: 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);
@ -38,10 +37,12 @@ public:
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;
wrapper_fb(drmModeFB2 *fb2, bool bModifiers)
: fb2 { fb2 },
fb_id { fb2->fb_id },
width { fb2->width }, height { fb2->height },
pixel_format { fb2->pixel_format },
modifier { bModifiers ? fb2->modifier : DRM_FORMAT_MOD_INVALID } {
memcpy(handles, fb2->handles, sizeof(handles));
memcpy(pitches, fb2->pitches, sizeof(pitches));
@ -225,12 +226,22 @@ public:
return 0;
}
fb_t fb(plane_t::pointer plane) {
auto fb = drmModeGetFB2(fd.el, plane->fb_id);
if(fb) {
return std::make_unique<wrapper_fb>(fb);
fb_t fb(plane_t::pointer plane, bool bModifiers) {
{
auto fb = drmModeGetFB2(fd.el, plane->fb_id);
if(fb) {
return std::make_unique<wrapper_fb>(fb, bModifiers);
}
}
return std::make_unique<wrapper_fb>(drmModeGetFB(fd.el, plane->fb_id));
{
auto fb = drmModeGetFB(fd.el, plane->fb_id);
if(fb) {
return std::make_unique<wrapper_fb>(fb);
}
}
return nullptr;
}
crtc_t crtc(std::uint32_t id) {
@ -408,6 +419,116 @@ void print(plane_t::pointer plane, fb_t::pointer fb, crtc_t::pointer crtc) {
BOOST_LOG(debug) << ss.str();
}
int init_sd(card_t &card, fb_t::pointer fb, file_t *files, egl::surface_descriptor_t *sd) {
auto obj_count = 4;
int x = 0;
for(int y = 0; y < 4; ++y) {
if(!fb->handles[y]) {
// It's not clear whether there could still be valid handles left.
// So, continue anyway.
// TODO: Is this redundent?
--obj_count;
continue;
}
files[x] = card.handleFD(fb->handles[x]);
if(files[x].el < 0) {
BOOST_LOG(error) << "Couldn't get primary file descriptor for Framebuffer ["sv << fb->fb_id << "]: "sv << strerror(errno);
return -1;
}
sd->fds[x] = files[x].el;
sd->offsets[x] = fb->offsets[y];
sd->pitches[x] = fb->pitches[y];
sd->plane_indices[x] = y;
++x;
}
sd->width = fb->width;
sd->height = fb->height;
sd->modifier = fb->modifier;
sd->fourcc = fb->pixel_format;
sd->obj_count = obj_count;
return 0;
}
/**
* Test the ability of the GPU card to import images.
*
* Returns:
* 1 --> It failed to import the image
* 0 --> It succeeded at importing the image
* -1 --> An error occurred
*/
int test_modifiers(card_t &card, plane_t::pointer plane, egl::display_t::pointer display, bool bModifiers) {
auto fb = card.fb(plane, bModifiers);
if(!fb) {
BOOST_LOG(error) << "Couldn't get drm fb for plane ["sv << plane->fb_id << "]: "sv << strerror(errno);
return -1;
}
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 -1;
}
file_t files[4];
egl::surface_descriptor_t sd;
if(init_sd(card, fb.get(), files, &sd)) {
return -1;
}
auto rgb_opt = egl::import_source(display, sd);
if(!rgb_opt) {
return 1;
}
return 0;
}
/**
* Test the ability of the GPU card to import images with modifiers
*
* Returns:
* 1 --> It doesn't support modifiers
* 0 --> It supports modifiers
* -1 --> An error occurred
*/
int test_modifiers(card_t &card, plane_t::pointer plane) {
if(!gbm::create_device) {
BOOST_LOG(warning) << "libgbm not initialized"sv;
return -1;
}
gbm::gbm_t gbm = gbm::create_device(card.fd.el);
if(!gbm) {
BOOST_LOG(error) << "Couldn't create GBM device: ["sv << util::hex(eglGetError()).to_string_view() << ']';
return -1;
}
auto display = egl::make_display(gbm.get());
if(!display) {
return -1;
}
auto ctx_opt = egl::make_ctx(display.get());
if(!ctx_opt) {
return -1;
}
auto status = test_modifiers(card, plane, display.get(), true);
if(status > 0) {
return test_modifiers(card, plane, display.get(), false);
}
return status;
}
class display_t : public platf::display_t {
public:
display_t(mem_type_e mem_type) : platf::display_t(), mem_type { mem_type } {}
@ -443,29 +564,15 @@ public:
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);
// If test_modifiers returns zero, than it supports modifiers
auto status = test_modifiers(card, plane.get());
if(status < 0) {
return -1;
}
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 -1;
}
bModifiers = status == 0;
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;
}
}
auto fb = card.fb(plane.get(), bModifiers);
BOOST_LOG(info) << "Found monitor for DRM screencasting"sv;
@ -481,8 +588,6 @@ public:
return -1;
}
//TODO: surf_sd = fb->to_sd();
auto crct = card.crtc(plane->crtc_id);
kms::print(plane.get(), fb.get(), crct.get());
@ -503,7 +608,7 @@ public:
offset_x = viewport.offset_x;
offset_y = viewport.offset_y;
}
// This code path shouldn't happend, but it's there just in case.
// This code path shouldn't have happend, but it's there just in case.
// crtc_to_monitor is part of the guesswork after all.
else {
BOOST_LOG(warning) << "Couldn't find crtc_id, this shouldn't have happened :\\"sv;
@ -537,7 +642,7 @@ public:
inline capture_e refresh(file_t *file, egl::surface_descriptor_t *sd) {
plane_t plane = drmModeGetPlane(card.fd.el, plane_id);
auto fb = card.fb(plane.get());
auto fb = card.fb(plane.get(), bModifiers);
if(!fb) {
BOOST_LOG(error) << "Couldn't get drm fb for plane ["sv << plane->fb_id << "]: "sv << strerror(errno);
return capture_e::error;
@ -549,37 +654,10 @@ public:
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;
++x;
if(init_sd(card, fb.get(), file, sd)) {
return capture_e::error;
}
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) {
@ -600,6 +678,10 @@ public:
card_t card;
// Some older GPU's may not support modifers, yet support FB2
// This flags wether it's capable of it.
bool bModifiers;
std::optional<x11::cursor_t> cursor_opt;
};
@ -958,7 +1040,8 @@ std::vector<std::string> kms_display_names() {
auto end = std::end(card);
for(auto plane = std::begin(card); plane != end; ++plane) {
auto fb = card.fb(plane.get());
// The framebuffer won't be imported to an openGL texture, so the boolean matters only for logging purposes
auto fb = card.fb(plane.get(), true);
if(!fb) {
BOOST_LOG(error) << "Couldn't get drm fb for plane ["sv << plane->fb_id << "]: "sv << strerror(errno);
continue;