mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-24 07:46:42 +00:00
parent
1a5f3a2210
commit
71f3e5f82a
@ -33,6 +33,10 @@ static struct task_struct * lx_update_task = NULL;
|
|||||||
static struct drm_client_dev * dev_client = NULL;
|
static struct drm_client_dev * dev_client = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
enum { CONNECTOR_ID_MIRROR = 15 };
|
||||||
|
static bool mirrored [16] = { };
|
||||||
|
|
||||||
|
|
||||||
static int user_register_fb(struct drm_client_dev const * const dev,
|
static int user_register_fb(struct drm_client_dev const * const dev,
|
||||||
struct fb_info * const info,
|
struct fb_info * const info,
|
||||||
struct drm_mode_fb_cmd2 const * const dumb_fb,
|
struct drm_mode_fb_cmd2 const * const dumb_fb,
|
||||||
@ -86,32 +90,32 @@ static inline bool fb_smaller_mode(struct fb_info const * const info,
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Heuristic to calculate max resolution across all mirrored connectors
|
* Heuristic to calculate mixed resolution across all mirrored connectors
|
||||||
*/
|
*/
|
||||||
static void preferred_mirror(struct drm_device const * const dev,
|
static void mirror_heuristic(struct drm_device const * const dev,
|
||||||
struct drm_display_mode * const prefer,
|
struct drm_display_mode * const virtual,
|
||||||
|
struct drm_display_mode * const compound,
|
||||||
struct drm_display_mode * const min_mode)
|
struct drm_display_mode * const min_mode)
|
||||||
{
|
{
|
||||||
struct drm_connector *connector = NULL;
|
struct drm_connector *connector = NULL;
|
||||||
struct drm_display_mode *mode = NULL;
|
struct drm_display_mode *mode = NULL;
|
||||||
unsigned connector_usable = 0;
|
|
||||||
struct drm_display_mode max_enforcement = { };
|
|
||||||
struct drm_connector_list_iter conn_iter;
|
struct drm_connector_list_iter conn_iter;
|
||||||
|
|
||||||
/* read Genode's config per connector */
|
/* read Genode's config per connector */
|
||||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||||
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
||||||
struct drm_display_mode smallest = { .hdisplay = ~0, .vdisplay = ~0 };
|
struct drm_display_mode smallest = { .hdisplay = ~0, .vdisplay = ~0 };
|
||||||
|
struct drm_display_mode usable = { };
|
||||||
struct genode_mode conf_mode = { };
|
struct genode_mode conf_mode = { };
|
||||||
unsigned mode_id = 0;
|
unsigned mode_id = 0;
|
||||||
|
|
||||||
/* check for connector configuration on Genode side */
|
/* check for connector configuration on Genode side */
|
||||||
lx_emul_i915_connector_config(connector->name, &conf_mode);
|
lx_emul_i915_connector_config(connector->name, &conf_mode);
|
||||||
|
|
||||||
if (!conf_mode.enabled)
|
if (!conf_mode.enabled || !conf_mode.mirror)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* look for smallest possible mode or if a specific mode is forced */
|
/* look for smallest possible mode or if a specific mode is specified */
|
||||||
list_for_each_entry(mode, &connector->modes, head) {
|
list_for_each_entry(mode, &connector->modes, head) {
|
||||||
mode_id ++;
|
mode_id ++;
|
||||||
|
|
||||||
@ -123,20 +127,21 @@ static void preferred_mirror(struct drm_device const * const dev,
|
|||||||
smallest.vdisplay = mode->vdisplay;
|
smallest.vdisplay = mode->vdisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!conf_mode.id)
|
/* maximal resolution enforcement */
|
||||||
|
if (conf_mode.max_width && conf_mode.max_height) {
|
||||||
|
if (conf_smaller_max_mode(&conf_mode, mode))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!mode || conf_mode.id != mode_id)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
conf_mode.width = mode->hdisplay;
|
|
||||||
conf_mode.height = mode->vdisplay;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode_id)
|
if (!usable.hdisplay && !usable.vdisplay)
|
||||||
connector_usable ++;
|
usable = *mode;
|
||||||
|
|
||||||
|
if (conf_mode.id == mode_id) {
|
||||||
|
conf_mode.width = mode->hdisplay;
|
||||||
|
conf_mode.height = mode->vdisplay;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If at least on mode is available, store smallest mode if it
|
* If at least on mode is available, store smallest mode if it
|
||||||
@ -145,8 +150,7 @@ static void preferred_mirror(struct drm_device const * const dev,
|
|||||||
if (mode_id && mode_larger(&smallest, min_mode))
|
if (mode_id && mode_larger(&smallest, min_mode))
|
||||||
*min_mode = smallest;
|
*min_mode = smallest;
|
||||||
|
|
||||||
if (conf_mode.mirror &&
|
if (conf_mode.force_width && conf_mode.force_height) {
|
||||||
conf_mode.force_width && conf_mode.force_height) {
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Even so the force_* mode is selected, a configured mode for
|
* Even so the force_* mode is selected, a configured mode for
|
||||||
@ -159,24 +163,23 @@ static void preferred_mirror(struct drm_device const * const dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* enforce the force mode */
|
/* enforce the force mode */
|
||||||
conf_mode.width = conf_mode.force_width;
|
virtual->hdisplay = conf_mode.force_width;
|
||||||
conf_mode.height = conf_mode.force_height;
|
virtual->vdisplay = conf_mode.force_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* maximal resolution enforcement */
|
/* compound calculation */
|
||||||
if (conf_mode.max_width && conf_mode.max_height) {
|
if (conf_mode.width && conf_mode.height) {
|
||||||
max_enforcement.hdisplay = conf_mode.max_width;
|
if (conf_mode.width > compound->hdisplay)
|
||||||
max_enforcement.vdisplay = conf_mode.max_height;
|
compound->hdisplay = conf_mode.width;
|
||||||
if (conf_smaller_max_mode(&conf_mode, prefer))
|
if (conf_mode.height > compound->vdisplay)
|
||||||
continue;
|
compound->vdisplay = conf_mode.height;
|
||||||
|
} else {
|
||||||
|
if (usable.hdisplay && usable.vdisplay) {
|
||||||
|
if (usable.hdisplay > compound->hdisplay)
|
||||||
|
compound->hdisplay = usable.hdisplay;
|
||||||
|
if (usable.vdisplay > compound->vdisplay)
|
||||||
|
compound->vdisplay = usable.vdisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!conf_mode.width || !conf_mode.height || !conf_mode.mirror)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (conf_larger_mode(&conf_mode, prefer)) {
|
|
||||||
prefer->hdisplay = conf_mode.width;
|
|
||||||
prefer->vdisplay = conf_mode.height;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drm_connector_list_iter_end(&conn_iter);
|
drm_connector_list_iter_end(&conn_iter);
|
||||||
@ -185,44 +188,9 @@ static void preferred_mirror(struct drm_device const * const dev,
|
|||||||
if (!min_mode->hdisplay || !min_mode->vdisplay)
|
if (!min_mode->hdisplay || !min_mode->vdisplay)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* we got a preferred resolution */
|
/* if no mirrored connectors are enabled, compound is the minimal mode */
|
||||||
if (prefer->hdisplay && prefer->vdisplay)
|
if (!compound->hdisplay || !compound->vdisplay)
|
||||||
return;
|
*compound = *min_mode;
|
||||||
|
|
||||||
/* if too large or nothing configured by Genode's config */
|
|
||||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
|
||||||
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
|
||||||
|
|
||||||
struct genode_mode conf_mode = { };
|
|
||||||
/* check for connector configuration on Genode side */
|
|
||||||
lx_emul_i915_connector_config(connector->name, &conf_mode);
|
|
||||||
|
|
||||||
list_for_each_entry(mode, &connector->modes, head) {
|
|
||||||
if (!mode)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (mode_larger(min_mode, mode))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (max_enforcement.hdisplay && max_enforcement.vdisplay) {
|
|
||||||
if (mode_larger(mode, &max_enforcement))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conf_mode.enabled && !conf_mode.mirror)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (mode_larger(mode, prefer)) {
|
|
||||||
prefer->hdisplay = mode->hdisplay;
|
|
||||||
prefer->vdisplay = mode->vdisplay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
drm_connector_list_iter_end(&conn_iter);
|
|
||||||
|
|
||||||
/* handle the "never should happen case" gracefully */
|
|
||||||
if (!prefer->hdisplay || !prefer->vdisplay)
|
|
||||||
*prefer = *min_mode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -492,6 +460,7 @@ static void close_unused_captures(struct drm_client_dev * const dev)
|
|||||||
/* report disconnected connectors to close capture connections */
|
/* report disconnected connectors to close capture connections */
|
||||||
struct drm_connector_list_iter conn_iter;
|
struct drm_connector_list_iter conn_iter;
|
||||||
struct drm_connector *connector = NULL;
|
struct drm_connector *connector = NULL;
|
||||||
|
bool mirror_in_use = false;
|
||||||
|
|
||||||
drm_connector_list_iter_begin(dev->dev, &conn_iter);
|
drm_connector_list_iter_begin(dev->dev, &conn_iter);
|
||||||
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
||||||
@ -520,6 +489,10 @@ static void close_unused_captures(struct drm_client_dev * const dev)
|
|||||||
if (unused) {
|
if (unused) {
|
||||||
struct fb_info fb_info = {};
|
struct fb_info fb_info = {};
|
||||||
|
|
||||||
|
if (connector->index < sizeof(mirrored) / sizeof(*mirrored))
|
||||||
|
mirrored[connector->index] = false;
|
||||||
|
|
||||||
|
fb_info.par = connector->name;
|
||||||
fb_info.var.bits_per_pixel = 32;
|
fb_info.var.bits_per_pixel = 32;
|
||||||
fb_info.node = connector->index;
|
fb_info.node = connector->index;
|
||||||
|
|
||||||
@ -527,6 +500,24 @@ static void close_unused_captures(struct drm_client_dev * const dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
drm_connector_list_iter_end(&conn_iter);
|
drm_connector_list_iter_end(&conn_iter);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < sizeof(mirrored) / sizeof(mirrored[0]); i++) {
|
||||||
|
if (!mirrored[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mirror_in_use = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mirror_in_use) {
|
||||||
|
struct fb_info fb_info = {};
|
||||||
|
|
||||||
|
fb_info.par = "mirror_capture";
|
||||||
|
fb_info.var.bits_per_pixel = 32;
|
||||||
|
fb_info.node = CONNECTOR_ID_MIRROR;
|
||||||
|
|
||||||
|
kernel_register_fb(&fb_info, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -534,9 +525,10 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
{
|
{
|
||||||
static struct drm_mode_create_dumb *gem_mirror = NULL;
|
static struct drm_mode_create_dumb *gem_mirror = NULL;
|
||||||
|
|
||||||
struct drm_display_mode mode_preferred = {};
|
struct drm_display_mode mirror_force = {};
|
||||||
struct drm_display_mode mode_minimum = {};
|
struct drm_display_mode mirror_compound = {};
|
||||||
struct drm_display_mode framebuffer = {};
|
struct drm_display_mode mirror_minimum = {};
|
||||||
|
struct drm_display_mode mirror_fb = {};
|
||||||
struct drm_mode_modeinfo user_mode = {};
|
struct drm_mode_modeinfo user_mode = {};
|
||||||
struct drm_display_mode * mode = NULL;
|
struct drm_display_mode * mode = NULL;
|
||||||
struct drm_mode_set * mode_set = NULL;
|
struct drm_mode_set * mode_set = NULL;
|
||||||
@ -557,34 +549,35 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
if (!dev || !dev->dev || !gem_mirror || !mirror_fb_cmd)
|
if (!dev || !dev->dev || !gem_mirror || !mirror_fb_cmd)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
preferred_mirror(dev->dev, &mode_preferred, &mode_minimum);
|
mirror_heuristic(dev->dev, &mirror_force, &mirror_compound,
|
||||||
|
&mirror_minimum);
|
||||||
|
|
||||||
if (!mode_minimum.hdisplay || !mode_minimum.vdisplay) {
|
if (!mirror_minimum.hdisplay || !mirror_minimum.vdisplay) {
|
||||||
/* no valid modes on any connector on early boot */
|
/* no valid modes on any connector on early boot */
|
||||||
if (!mirror_fb_cmd->fb_id)
|
if (!mirror_fb_cmd->fb_id)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* valid connectors but all are disabled by config */
|
/* valid connectors but all are disabled by config */
|
||||||
mode_minimum.hdisplay = mirror_fb_cmd->width;
|
mirror_minimum.hdisplay = mirror_fb_cmd->width;
|
||||||
mode_minimum.vdisplay = mirror_fb_cmd->height;
|
mirror_minimum.vdisplay = mirror_fb_cmd->height;
|
||||||
mode_preferred = mode_minimum;
|
mirror_compound = mirror_minimum;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode_larger(&mode_preferred, &mode_minimum))
|
if (mode_larger(&mirror_compound, &mirror_minimum))
|
||||||
framebuffer = mode_preferred;
|
mirror_fb = mirror_compound;
|
||||||
else
|
else
|
||||||
framebuffer = mode_minimum;
|
mirror_fb = mirror_minimum;
|
||||||
|
|
||||||
{
|
{
|
||||||
int const err = check_resize_fb(dev,
|
int const err = check_resize_fb(dev,
|
||||||
gem_mirror,
|
gem_mirror,
|
||||||
mirror_fb_cmd,
|
mirror_fb_cmd,
|
||||||
framebuffer.hdisplay,
|
mirror_fb.hdisplay,
|
||||||
framebuffer.vdisplay);
|
mirror_fb.vdisplay);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
printk("setting up framebuffer of %ux%u failed - error=%d\n",
|
printk("setting up mirrored framebuffer of %ux%u failed - error=%d\n",
|
||||||
framebuffer.hdisplay, framebuffer.vdisplay, err);
|
mirror_fb.hdisplay, mirror_fb.vdisplay, err);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -595,10 +588,10 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
return retry;
|
return retry;
|
||||||
|
|
||||||
/* prepare fb info for kernel_register_fb() evaluated by Genode side */
|
/* prepare fb info for kernel_register_fb() evaluated by Genode side */
|
||||||
info.var.xres = framebuffer.hdisplay;
|
info.var.xres = mirror_fb.hdisplay;
|
||||||
info.var.yres = framebuffer.vdisplay;
|
info.var.yres = mirror_fb.vdisplay;
|
||||||
info.var.xres_virtual = mode_preferred.hdisplay;
|
info.var.xres_virtual = mirror_force.hdisplay ? : mirror_compound.hdisplay;
|
||||||
info.var.yres_virtual = mode_preferred.vdisplay;
|
info.var.yres_virtual = mirror_force.vdisplay ? : mirror_compound.vdisplay;
|
||||||
|
|
||||||
drm_client_for_each_modeset(mode_set, dev) {
|
drm_client_for_each_modeset(mode_set, dev) {
|
||||||
struct drm_display_mode * mode_match = NULL;
|
struct drm_display_mode * mode_match = NULL;
|
||||||
@ -624,8 +617,8 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
if (!mode)
|
if (!mode)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* allocated framebuffer smaller than mode can't be used */
|
/* allocated mirrored framebufer smaller than mode can't be used */
|
||||||
if (fb_smaller_mode(&info, mode))
|
if (conf_mode.mirror && fb_smaller_mode(&info, mode))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* use mode id if configured and matches exactly */
|
/* use mode id if configured and matches exactly */
|
||||||
@ -634,13 +627,13 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
mode_match = mode;
|
mode_match = mode;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if invalid, mode is configured in second loop below */
|
/* if invalid, mode is configured in second loop below */
|
||||||
if (conf_mode.width == 0 || conf_mode.height == 0) {
|
if (conf_mode.width == 0 || conf_mode.height == 0)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
/* no exact match by mode id -> try matching by size */
|
/* no exact match by mode id -> try matching by size */
|
||||||
if ((mode->hdisplay != conf_mode.width) ||
|
if ((mode->hdisplay != conf_mode.width) ||
|
||||||
@ -659,6 +652,10 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
mode_match = mode;
|
mode_match = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* track whether connector is used mirrored or discrete */
|
||||||
|
if (connector->index < sizeof(mirrored) / sizeof(*mirrored))
|
||||||
|
mirrored[connector->index] = conf_mode.enabled && conf_mode.mirror;
|
||||||
|
|
||||||
/* apply new mode */
|
/* apply new mode */
|
||||||
mode_id = 0;
|
mode_id = 0;
|
||||||
list_for_each_entry(mode, &connector->modes, head) {
|
list_for_each_entry(mode, &connector->modes, head) {
|
||||||
@ -690,7 +687,7 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
if (!mode_match) {
|
if (!mode_match) {
|
||||||
|
|
||||||
/* fb smaller than mode is denied by drm_mode_setcrtc */
|
/* fb smaller than mode is denied by drm_mode_setcrtc */
|
||||||
if (fb_smaller_mode(&fb_info, mode))
|
if (conf_mode.enabled && fb_smaller_mode(&fb_info, mode))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* use first smaller mode */
|
/* use first smaller mode */
|
||||||
@ -723,7 +720,7 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
mode, fb, connector);
|
mode, fb, connector);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert kernel internal mode to user mode expectecd via ioctl */
|
/* convert kernel internal mode to user mode expected via ioctl */
|
||||||
drm_mode_convert_to_umode(&user_mode, mode);
|
drm_mode_convert_to_umode(&user_mode, mode);
|
||||||
|
|
||||||
/* assign fb & connector to crtc with specified mode */
|
/* assign fb & connector to crtc with specified mode */
|
||||||
@ -742,12 +739,13 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
if (!retry)
|
if (!retry)
|
||||||
retry = !!err;
|
retry = !!err;
|
||||||
|
|
||||||
if (!err && conf_mode.mirror && !mirror.report) {
|
if (!err && conf_mode.enabled && conf_mode.mirror && !mirror.report) {
|
||||||
/* use fb_info of first mirrored screen */
|
/* use fb_info of first mirrored screen */
|
||||||
mirror.report = true;
|
mirror.report = true;
|
||||||
mirror.width_mm = mode->width_mm;
|
mirror.width_mm = mode->width_mm;
|
||||||
mirror.height_mm = mode->height_mm;
|
mirror.height_mm = mode->height_mm;
|
||||||
mirror.info = fb_info;
|
mirror.info = fb_info;
|
||||||
|
mirror.info.node = CONNECTOR_ID_MIRROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* diagnostics */
|
/* diagnostics */
|
||||||
@ -759,7 +757,7 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
conf_mode.mirror ? " mirror " : " discrete",
|
conf_mode.mirror ? " mirror " : " discrete",
|
||||||
mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode),
|
mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode),
|
||||||
drm_mode_vrefresh(mode) < 100 ? " ": "",
|
drm_mode_vrefresh(mode) < 100 ? " ": "",
|
||||||
framebuffer.hdisplay, framebuffer.vdisplay,
|
fb_info.var.xres, fb_info.var.yres,
|
||||||
(err || no_match) ? "" : "\n");
|
(err || no_match) ? "" : "\n");
|
||||||
|
|
||||||
if (no_match)
|
if (no_match)
|
||||||
@ -769,7 +767,7 @@ static bool reconfigure(struct drm_client_dev * const dev)
|
|||||||
if (err)
|
if (err)
|
||||||
printk(" - failed, error=%d\n", err);
|
printk(" - failed, error=%d\n", err);
|
||||||
|
|
||||||
if (!err && !conf_mode.mirror)
|
if (!err && !conf_mode.mirror && conf_mode.enabled)
|
||||||
user_register_fb(dev, &fb_info, &fb_cmd,
|
user_register_fb(dev, &fb_info, &fb_cmd,
|
||||||
mode->width_mm, mode->height_mm);
|
mode->width_mm, mode->height_mm);
|
||||||
|
|
||||||
@ -841,6 +839,7 @@ static void mark_framebuffer_dirty(struct drm_framebuffer * const fb)
|
|||||||
enum { CAPTURE_RATE_MS = 10, ATTEMPTS_BEFORE_STOP = 7 };
|
enum { CAPTURE_RATE_MS = 10, ATTEMPTS_BEFORE_STOP = 7 };
|
||||||
static unsigned unchanged[16] = { };
|
static unsigned unchanged[16] = { };
|
||||||
|
|
||||||
|
|
||||||
void lx_emul_i915_wakeup(unsigned const connector_id)
|
void lx_emul_i915_wakeup(unsigned const connector_id)
|
||||||
{
|
{
|
||||||
bool const valid_id = connector_id < sizeof(unchanged) / sizeof(*unchanged);
|
bool const valid_id = connector_id < sizeof(unchanged) / sizeof(*unchanged);
|
||||||
@ -864,6 +863,7 @@ static int update_content(void *)
|
|||||||
struct drm_connector *connector = NULL;
|
struct drm_connector *connector = NULL;
|
||||||
struct drm_device const *dev = dev_client->dev;
|
struct drm_device const *dev = dev_client->dev;
|
||||||
bool block_task = true;
|
bool block_task = true;
|
||||||
|
bool mirror_run = false;
|
||||||
|
|
||||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||||
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
drm_client_for_each_connector_iter(connector, &conn_iter) {
|
||||||
@ -873,20 +873,29 @@ static int update_content(void *)
|
|||||||
|
|
||||||
int err = -1;
|
int err = -1;
|
||||||
bool may_sleep = false;
|
bool may_sleep = false;
|
||||||
bool const valid_id = connector->index < sizeof(unchanged) / sizeof(*unchanged);
|
unsigned index = connector->index;
|
||||||
|
|
||||||
if (connector->status != connector_status_connected)
|
if (connector->status != connector_status_connected)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (valid_id)
|
if (connector->index >= sizeof(unchanged) / sizeof(*unchanged)) {
|
||||||
unchanged[connector->index] ++;
|
printk("%s: connector id invalid %d\n", __func__, index);
|
||||||
else
|
index = CONNECTOR_ID_MIRROR; /* should never happen case */
|
||||||
printk("%s: connector id invalid %d\n", __func__, connector->index);
|
}
|
||||||
|
|
||||||
if (valid_id)
|
if (mirrored[index] && mirror_run)
|
||||||
may_sleep = unchanged[connector->index] >= ATTEMPTS_BEFORE_STOP;
|
continue;
|
||||||
|
|
||||||
if (!lx_emul_i915_blit(connector->index, may_sleep)) {
|
if (mirrored[index]) {
|
||||||
|
mirror_run = true;
|
||||||
|
index = CONNECTOR_ID_MIRROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
unchanged[index] ++;
|
||||||
|
|
||||||
|
may_sleep = unchanged[index] >= ATTEMPTS_BEFORE_STOP;
|
||||||
|
|
||||||
|
if (!lx_emul_i915_blit(index, may_sleep)) {
|
||||||
if (!may_sleep)
|
if (!may_sleep)
|
||||||
block_task = false;
|
block_task = false;
|
||||||
|
|
||||||
@ -895,8 +904,7 @@ static int update_content(void *)
|
|||||||
|
|
||||||
block_task = false;
|
block_task = false;
|
||||||
|
|
||||||
if (valid_id)
|
unchanged[index] = 0;
|
||||||
unchanged[connector->index] = 0;
|
|
||||||
|
|
||||||
if (!connector->state || !connector->state->crtc)
|
if (!connector->state || !connector->state->crtc)
|
||||||
continue;
|
continue;
|
||||||
@ -1112,8 +1120,8 @@ static int fb_client_hotplug(struct drm_client_dev *client)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (Re-)assign framebuffer to modeset (lost due to modeset_probe) and
|
* (Re-)assign mirrored framebuffer to modeset (lost due to modeset_probe)
|
||||||
* commit the change.
|
* and commit the change.
|
||||||
*/
|
*/
|
||||||
if (fb_mirror) {
|
if (fb_mirror) {
|
||||||
struct drm_framebuffer * free_fbs[MAX_FBS] = { };
|
struct drm_framebuffer * free_fbs[MAX_FBS] = { };
|
||||||
|
@ -345,6 +345,7 @@ void Framebuffer::Driver::generate_report()
|
|||||||
lx_emul_i915_report_discrete(&xml);
|
lx_emul_i915_report_discrete(&xml);
|
||||||
|
|
||||||
xml.node("merge", [&] () {
|
xml.node("merge", [&] () {
|
||||||
|
xml.attribute("name", merge_label);
|
||||||
node.with_optional_sub_node("merge", [&](auto const &merge) {
|
node.with_optional_sub_node("merge", [&](auto const &merge) {
|
||||||
with_force(merge, [&](unsigned width, unsigned height) {
|
with_force(merge, [&](unsigned width, unsigned height) {
|
||||||
xml.attribute("width", width);
|
xml.attribute("width", width);
|
||||||
@ -371,7 +372,15 @@ void Framebuffer::Driver::lookup_config(char const * const name,
|
|||||||
mode.brightness = 70; /* percent */
|
mode.brightness = 70; /* percent */
|
||||||
mode.mirror = true;
|
mode.mirror = true;
|
||||||
|
|
||||||
if (!config.valid() || disable_all)
|
if (!config.valid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
with_max_enforcement([&](unsigned const width, unsigned const height) {
|
||||||
|
mode.max_width = width;
|
||||||
|
mode.max_height = height;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (disable_all)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto for_each_node = [&](auto const &node, bool const mirror){
|
auto for_each_node = [&](auto const &node, bool const mirror){
|
||||||
@ -417,11 +426,6 @@ void Framebuffer::Driver::lookup_config(char const * const name,
|
|||||||
|
|
||||||
mirror_node = true;
|
mirror_node = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
with_max_enforcement([&](unsigned const width, unsigned const height) {
|
|
||||||
mode.max_width = width;
|
|
||||||
mode.max_height = height;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -459,8 +463,6 @@ void lx_emul_i915_framebuffer_ready(unsigned const connector_id,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
new (drv.heap) Connector (env, drv.ids, id);
|
new (drv.heap) Connector (env, drv.ids, id);
|
||||||
|
|
||||||
lx_emul_i915_wakeup(unsigned(id.value));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
drv.ids.apply<Connector>(id, [&](Connector &conn) {
|
drv.ids.apply<Connector>(id, [&](Connector &conn) {
|
||||||
@ -468,8 +470,6 @@ void lx_emul_i915_framebuffer_ready(unsigned const connector_id,
|
|||||||
Capture::Area area (xres, yres);
|
Capture::Area area (xres, yres);
|
||||||
Capture::Area area_phys(phys_width, phys_height);
|
Capture::Area area_phys(phys_width, phys_height);
|
||||||
|
|
||||||
auto const prev_size = conn.size;
|
|
||||||
|
|
||||||
auto label = !conn_name
|
auto label = !conn_name
|
||||||
? Capture::Connection::Label(conn.id_element)
|
? Capture::Connection::Label(conn.id_element)
|
||||||
: Capture::Connection::Label(conn_name) == "mirror_capture"
|
: Capture::Connection::Label(conn_name) == "mirror_capture"
|
||||||
@ -479,22 +479,28 @@ void lx_emul_i915_framebuffer_ready(unsigned const connector_id,
|
|||||||
bool const same = drv.update(conn, Genode::addr_t(base), area,
|
bool const same = drv.update(conn, Genode::addr_t(base), area,
|
||||||
area_phys, { mm_width, mm_height}, label);
|
area_phys, { mm_width, mm_height}, label);
|
||||||
|
|
||||||
if (same)
|
if (same) {
|
||||||
|
lx_emul_i915_wakeup(unsigned(id.value));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* clear artefacts */
|
/* clear artefacts */
|
||||||
if (base && (area != area_phys))
|
if (base && (area != area_phys))
|
||||||
Genode::memset(base, 0, area_phys.count() * 4);
|
Genode::memset(base, 0, area_phys.count() * 4);
|
||||||
|
|
||||||
if (conn.size.valid())
|
String<12> space { };
|
||||||
log("setup - framebuffer ",
|
for (auto i = label.length(); i < space.capacity() - 1; i++) {
|
||||||
" - connector id=", conn.id_element.id().value,
|
space = String<12>(" ", space);
|
||||||
", virtual=", xres, "x", yres,
|
}
|
||||||
", physical=", phys_width, "x", phys_height);
|
|
||||||
else
|
if (conn.size.valid()) {
|
||||||
log("free - framebuffer ",
|
log(space, label, ": capture ", xres, "x", yres, " with "
|
||||||
" - connector id=", conn.id_element.id().value,
|
" framebuffer ", phys_width, "x", phys_height);
|
||||||
", ", prev_size);
|
|
||||||
|
lx_emul_i915_wakeup(unsigned(id.value));
|
||||||
|
} else
|
||||||
|
log(space, label, ": capture closed ");
|
||||||
|
|
||||||
}, [](){ /* unknown id */ });
|
}, [](){ /* unknown id */ });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user