backends/x11/nested: Emulate per CRTC drawing

Make the nested backend emulate how the real backends actually draw,
i.e. by drawing each CRTC separately. This makes it possible to test
different configuration paths that can take place on different
hardware, without having said hardware.

For example, by setting MUTTER_DEBUG_TILED_DUMMY_MONITORS and
MUTTER_DEBUG_NESTED_OFFSCREEN_TRANSFORM to "1", one can test a system
with MST (tiled) monitors where the GPU doesn't support some transform.

https://bugzilla.gnome.org/show_bug.cgi?id=777732
This commit is contained in:
Jonas Ådahl 2017-03-21 14:38:35 +08:00
parent 0ac2eba4d3
commit 9787b1cfd5
2 changed files with 170 additions and 13 deletions

View File

@ -27,6 +27,8 @@
#include "backends/x11/meta-stage-x11-nested.h" #include "backends/x11/meta-stage-x11-nested.h"
#include "backends/meta-backend-private.h" #include "backends/meta-backend-private.h"
#include "backends/meta-logical-monitor.h"
#include "backends/meta-monitor.h"
#include "backends/meta-renderer.h" #include "backends/meta-renderer.h"
#include "backends/x11/nested/meta-renderer-x11-nested.h" #include "backends/x11/nested/meta-renderer-x11-nested.h"
#include "clutter/clutter-mutter.h" #include "clutter/clutter-mutter.h"
@ -88,6 +90,149 @@ meta_stage_x11_nested_get_views (ClutterStageWindow *stage_window)
return meta_renderer_get_views (renderer); return meta_renderer_get_views (renderer);
} }
typedef struct
{
MetaStageX11Nested *stage_nested;
CoglTexture *texture;
ClutterStageView *view;
MetaLogicalMonitor *logical_monitor;
} DrawCrtcData;
static gboolean
draw_crtc (MetaMonitor *monitor,
MetaMonitorMode *monitor_mode,
MetaMonitorCrtcMode *monitor_crtc_mode,
gpointer user_data,
GError **error)
{
DrawCrtcData *data = user_data;
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (data->stage_nested);
CoglFramebuffer *onscreen = COGL_FRAMEBUFFER (stage_x11->onscreen);
CoglTexture *texture = data->texture;
MetaLogicalMonitor *logical_monitor = data->logical_monitor;
MetaOutput *output = monitor_crtc_mode->output;
MetaCrtc *crtc = output->crtc;
MetaRendererView *renderer_view = META_RENDERER_VIEW (data->view);
MetaMonitorTransform view_transform;
MetaMonitorTransform layout_transform = META_MONITOR_TRANSFORM_NORMAL;
cairo_rectangle_int_t view_layout;
CoglMatrix projection_matrix;
CoglMatrix transform;
float texture_width, texture_height;
float sample_x, sample_y, sample_width, sample_height;
int viewport_x, viewport_y;
int viewport_width, viewport_height;
float s_1, t_1, s_2, t_2;
texture_width = cogl_texture_get_width (texture);
texture_height = cogl_texture_get_height (texture);
clutter_stage_view_get_layout (data->view, &view_layout);
sample_x = crtc->rect.x - view_layout.x;
sample_y = crtc->rect.y - view_layout.y;
sample_width = crtc->rect.width;
sample_height = crtc->rect.height;
clutter_stage_view_get_offscreen_transformation_matrix (data->view,
&transform);
cogl_framebuffer_push_matrix (onscreen);
cogl_matrix_init_identity (&projection_matrix);
cogl_matrix_translate (&projection_matrix, -1, 1, 0);
cogl_matrix_scale (&projection_matrix, 2, -2, 0);
cogl_matrix_multiply (&projection_matrix, &projection_matrix, &transform);
cogl_framebuffer_set_projection_matrix (onscreen, &projection_matrix);
s_1 = sample_x / texture_width;
t_1 = sample_y / texture_height;
s_2 = (sample_x + sample_width) / texture_width;
t_2 = (sample_y + sample_height) / texture_height;
view_transform = meta_renderer_view_get_transform (renderer_view);
if (view_transform == logical_monitor->transform)
{
switch (view_transform)
{
case META_MONITOR_TRANSFORM_NORMAL:
case META_MONITOR_TRANSFORM_FLIPPED:
layout_transform = META_MONITOR_TRANSFORM_NORMAL;
break;
case META_MONITOR_TRANSFORM_270:
case META_MONITOR_TRANSFORM_FLIPPED_270:
layout_transform = META_MONITOR_TRANSFORM_90;
break;
case META_MONITOR_TRANSFORM_180:
case META_MONITOR_TRANSFORM_FLIPPED_180:
layout_transform = META_MONITOR_TRANSFORM_180;
break;
case META_MONITOR_TRANSFORM_90:
case META_MONITOR_TRANSFORM_FLIPPED_90:
layout_transform = META_MONITOR_TRANSFORM_270;
break;
}
}
else
{
layout_transform = logical_monitor->transform;
}
meta_monitor_calculate_crtc_pos (monitor, monitor_mode, output,
layout_transform,
&viewport_x,
&viewport_y);
viewport_x += logical_monitor->rect.x;
viewport_y += logical_monitor->rect.y;
if (meta_monitor_transform_is_rotated (logical_monitor->transform))
{
viewport_width = monitor_crtc_mode->crtc_mode->height;
viewport_height = monitor_crtc_mode->crtc_mode->width;
}
else
{
viewport_width = monitor_crtc_mode->crtc_mode->width;
viewport_height = monitor_crtc_mode->crtc_mode->height;
}
cogl_framebuffer_set_viewport (onscreen,
viewport_x, viewport_y,
viewport_width, viewport_height);
cogl_framebuffer_draw_textured_rectangle (onscreen,
data->stage_nested->pipeline,
0, 0, 1, 1,
s_1, t_1, s_2, t_2);
cogl_framebuffer_pop_matrix (onscreen);
return TRUE;
}
static void
draw_logical_monitor (MetaStageX11Nested *stage_nested,
MetaLogicalMonitor *logical_monitor,
CoglTexture *texture,
ClutterStageView *view,
cairo_rectangle_int_t *view_layout)
{
MetaMonitor *monitor;
MetaMonitorMode *current_mode;
cogl_pipeline_set_layer_wrap_mode (stage_nested->pipeline, 0,
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
current_mode = meta_monitor_get_current_mode (monitor);
meta_monitor_mode_foreach_crtc (monitor, current_mode,
draw_crtc,
&(DrawCrtcData) {
.stage_nested = stage_nested,
.texture = texture,
.view = view,
.logical_monitor = logical_monitor
},
NULL);
}
static void static void
meta_stage_x11_nested_finish_frame (ClutterStageWindow *stage_window) meta_stage_x11_nested_finish_frame (ClutterStageWindow *stage_window)
{ {
@ -109,29 +254,40 @@ meta_stage_x11_nested_finish_frame (ClutterStageWindow *stage_window)
for (l = meta_renderer_get_views (renderer); l; l = l->next) for (l = meta_renderer_get_views (renderer); l; l = l->next)
{ {
ClutterStageView *view = l->data; ClutterStageView *view = l->data;
MetaRendererView *renderer_view = META_RENDERER_VIEW (view);
MetaLogicalMonitor *logical_monitor;
cairo_rectangle_int_t view_layout; cairo_rectangle_int_t view_layout;
CoglFramebuffer *framebuffer; CoglFramebuffer *framebuffer;
CoglTexture *texture; CoglTexture *texture;
CoglMatrix matrix;
clutter_stage_view_get_layout (view, &view_layout); clutter_stage_view_get_layout (view, &view_layout);
framebuffer = clutter_stage_view_get_onscreen (view); framebuffer = clutter_stage_view_get_onscreen (view);
texture = cogl_offscreen_get_texture (COGL_OFFSCREEN (framebuffer)); texture = cogl_offscreen_get_texture (COGL_OFFSCREEN (framebuffer));
clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
cogl_matrix_get_inverse (&matrix, &matrix);
cogl_pipeline_set_layer_matrix (stage_nested->pipeline, 0, &matrix);
cogl_framebuffer_set_viewport (onscreen,
view_layout.x,
view_layout.y,
view_layout.width,
view_layout.height);
cogl_pipeline_set_layer_texture (stage_nested->pipeline, 0, texture); cogl_pipeline_set_layer_texture (stage_nested->pipeline, 0, texture);
cogl_framebuffer_draw_rectangle (onscreen,
stage_nested->pipeline, logical_monitor = meta_renderer_view_get_logical_monitor (renderer_view);
-1, 1, 1, -1); if (logical_monitor)
{
draw_logical_monitor (stage_nested, logical_monitor, texture, view, &view_layout);
}
else
{
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
GList *logical_monitors;
GList *k;
logical_monitors =
meta_monitor_manager_get_logical_monitors (monitor_manager);
for (k = logical_monitors; k; k = k->next)
{
logical_monitor = k->data;
draw_logical_monitor (stage_nested, logical_monitor, texture, view, &view_layout);
}
}
} }
cogl_onscreen_swap_buffers (stage_x11->onscreen); cogl_onscreen_swap_buffers (stage_x11->onscreen);

View File

@ -211,6 +211,7 @@ meta_renderer_x11_nested_create_view (MetaRenderer *renderer,
"offscreen", COGL_FRAMEBUFFER (offscreen), "offscreen", COGL_FRAMEBUFFER (offscreen),
"transform", view_transform, "transform", view_transform,
"scale", view_scale, "scale", view_scale,
"logical-monitor", logical_monitor,
NULL); NULL);
} }