From 9787b1cfd5c646b1280f2335f81a80ebda94b721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 21 Mar 2017 14:38:35 +0800 Subject: [PATCH] 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 --- src/backends/x11/meta-stage-x11-nested.c | 182 ++++++++++++++++-- .../x11/nested/meta-renderer-x11-nested.c | 1 + 2 files changed, 170 insertions(+), 13 deletions(-) diff --git a/src/backends/x11/meta-stage-x11-nested.c b/src/backends/x11/meta-stage-x11-nested.c index b2732c345..cf3b92029 100644 --- a/src/backends/x11/meta-stage-x11-nested.c +++ b/src/backends/x11/meta-stage-x11-nested.c @@ -27,6 +27,8 @@ #include "backends/x11/meta-stage-x11-nested.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/x11/nested/meta-renderer-x11-nested.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); } +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 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) { ClutterStageView *view = l->data; + MetaRendererView *renderer_view = META_RENDERER_VIEW (view); + MetaLogicalMonitor *logical_monitor; cairo_rectangle_int_t view_layout; CoglFramebuffer *framebuffer; CoglTexture *texture; - CoglMatrix matrix; clutter_stage_view_get_layout (view, &view_layout); framebuffer = clutter_stage_view_get_onscreen (view); 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_framebuffer_draw_rectangle (onscreen, - stage_nested->pipeline, - -1, 1, 1, -1); + + logical_monitor = meta_renderer_view_get_logical_monitor (renderer_view); + 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); diff --git a/src/backends/x11/nested/meta-renderer-x11-nested.c b/src/backends/x11/nested/meta-renderer-x11-nested.c index 8162062d6..884325214 100644 --- a/src/backends/x11/nested/meta-renderer-x11-nested.c +++ b/src/backends/x11/nested/meta-renderer-x11-nested.c @@ -211,6 +211,7 @@ meta_renderer_x11_nested_create_view (MetaRenderer *renderer, "offscreen", COGL_FRAMEBUFFER (offscreen), "transform", view_transform, "scale", view_scale, + "logical-monitor", logical_monitor, NULL); }