aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar emersion <contact@emersion.fr>2018-04-06 13:27:01 -0400
committerLibravatar emersion <contact@emersion.fr>2018-04-06 13:27:01 -0400
commite550e22c0b6e2192f2750a6e13356980426d26ba (patch)
tree2ff2cb25fd718e84b2b393b5b805a390d8475d49
parentSimplify damage tracking functions, use them in layer shell (diff)
downloadsway-e550e22c0b6e2192f2750a6e13356980426d26ba.tar.gz
sway-e550e22c0b6e2192f2750a6e13356980426d26ba.tar.zst
sway-e550e22c0b6e2192f2750a6e13356980426d26ba.zip
Refactor rendering code
-rw-r--r--sway/desktop/output.c334
1 files changed, 160 insertions, 174 deletions
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 3bbd0bb2..90ec3c77 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -38,191 +38,201 @@ struct sway_container *output_by_name(const char *name) {
38 */ 38 */
39static void rotate_child_position(double *sx, double *sy, double sw, double sh, 39static void rotate_child_position(double *sx, double *sy, double sw, double sh,
40 double pw, double ph, float rotation) { 40 double pw, double ph, float rotation) {
41 if (rotation != 0.0) { 41 if (rotation == 0.0f) {
42 // Coordinates relative to the center of the subsurface 42 return;
43 double ox = *sx - pw/2 + sw/2,
44 oy = *sy - ph/2 + sh/2;
45 // Rotated coordinates
46 double rx = cos(-rotation)*ox - sin(-rotation)*oy,
47 ry = cos(-rotation)*oy + sin(-rotation)*ox;
48 *sx = rx + pw/2 - sw/2;
49 *sy = ry + ph/2 - sh/2;
50 } 43 }
44
45 // Coordinates relative to the center of the subsurface
46 double ox = *sx - pw/2 + sw/2,
47 oy = *sy - ph/2 + sh/2;
48 // Rotated coordinates
49 double rx = cos(-rotation)*ox - sin(-rotation)*oy,
50 ry = cos(-rotation)*oy + sin(-rotation)*ox;
51 *sx = rx + pw/2 - sw/2;
52 *sy = ry + ph/2 - sh/2;
51} 53}
52 54
53/** 55/**
54 * Checks whether a surface at (lx, ly) intersects an output. If `box` is not 56 * Contains a surface's root geometry information. For instance, when rendering
55 * NULL, it populates it with the surface box in the output, in output-local 57 * a popup, this will contain the parent view's position and size.
56 * coordinates.
57 */ 58 */
58static bool surface_intersect_output(struct wlr_surface *surface, 59struct root_geometry {
59 struct wlr_output_layout *output_layout, struct wlr_output *wlr_output, 60 double x, y;
60 double ox, double oy, float rotation, struct wlr_box *box) { 61 int width, height;
61 if (box != NULL) { 62 float rotation;
62 box->x = ox * wlr_output->scale; 63};
63 box->y = oy * wlr_output->scale; 64
64 box->width = surface->current->width * wlr_output->scale; 65static bool get_surface_box(struct root_geometry *geo,
65 box->height = surface->current->height * wlr_output->scale; 66 struct sway_output *output, struct wlr_surface *surface, int sx, int sy,
67 struct wlr_box *surface_box) {
68 int sw = surface->current->width;
69 int sh = surface->current->height;
70
71 double _sx = sx, _sy = sy;
72 rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height,
73 geo->rotation);
74
75 struct wlr_box box = {
76 .x = geo->x + _sx,
77 .y = geo->y + _sy,
78 .width = sw,
79 .height = sh,
80 };
81 if (surface_box != NULL) {
82 memcpy(surface_box, &box, sizeof(struct wlr_box));
66 } 83 }
67 84
68 struct wlr_box layout_box = { 85 struct wlr_box rotated_box;
69 .x = wlr_output->lx + ox, .y = wlr_output->ly + oy, 86 wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box);
70 .width = surface->current->width, .height = surface->current->height, 87
88 struct wlr_box output_box = {
89 .width = output->swayc->width,
90 .height = output->swayc->height,
71 }; 91 };
72 wlr_box_rotated_bounds(&layout_box, rotation, &layout_box); 92
73 return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); 93 struct wlr_box intersection;
94 return wlr_box_intersection(&output_box, &rotated_box, &intersection);
74} 95}
75 96
76static void render_surface(struct wlr_surface *surface, 97static void output_surface_for_each_surface(struct wlr_surface *surface,
77 struct wlr_output *wlr_output, struct timespec *when, 98 double ox, double oy, float rotation, struct root_geometry *geo,
78 double ox, double oy, float rotation, float alpha) { 99 wlr_surface_iterator_func_t iterator, void *user_data) {
79 struct wlr_renderer *renderer = 100 geo->x = ox;
80 wlr_backend_get_renderer(wlr_output->backend); 101 geo->y = oy;
102 geo->width = surface->current->width;
103 geo->height = surface->current->height;
104 geo->rotation = rotation;
105
106 wlr_surface_for_each_surface(surface, iterator, user_data);
107}
108
109static void output_view_for_each_surface(struct sway_view *view,
110 struct root_geometry *geo, wlr_surface_iterator_func_t iterator,
111 void *user_data) {
112 geo->x = view->swayc->x;
113 geo->y = view->swayc->y;
114 geo->width = view->surface->current->width;
115 geo->height = view->surface->current->height;
116 geo->rotation = 0; // TODO
117
118 view_for_each_surface(view, iterator, user_data);
119}
120
121static void scale_box(struct wlr_box *box, float scale) {
122 box->x *= scale;
123 box->y *= scale;
124 box->width *= scale;
125 box->height *= scale;
126}
127
128struct render_data {
129 struct root_geometry root_geo;
130 struct sway_output *output;
131 struct timespec *when;
132 float alpha;
133};
134
135static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy,
136 void *_data) {
137 struct render_data *data = _data;
138 struct wlr_output *wlr_output = data->output->wlr_output;
139 struct timespec *when = data->when;
140 float rotation = data->root_geo.rotation;
141 float alpha = data->alpha;
81 142
82 if (!wlr_surface_has_buffer(surface)) { 143 if (!wlr_surface_has_buffer(surface)) {
83 return; 144 return;
84 } 145 }
85 146
86 struct wlr_output_layout *layout = root_container.sway_root->output_layout;
87
88 struct wlr_box box; 147 struct wlr_box box;
89 bool intersects = surface_intersect_output(surface, layout, wlr_output, 148 bool intersects = get_surface_box(&data->root_geo, data->output, surface,
90 ox, oy, rotation, &box); 149 sx, sy, &box);
91 if (intersects) { 150 if (!intersects) {
92 float matrix[9]; 151 return;
93 enum wl_output_transform transform =
94 wlr_output_transform_invert(surface->current->transform);
95 wlr_matrix_project_box(matrix, &box, transform, rotation,
96 wlr_output->transform_matrix);
97
98 wlr_render_texture_with_matrix(renderer, surface->texture,
99 matrix, alpha);
100
101 wlr_surface_send_frame_done(surface, when);
102 } 152 }
103 153
104 struct wlr_subsurface *subsurface; 154 struct wlr_renderer *renderer =
105 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { 155 wlr_backend_get_renderer(wlr_output->backend);
106 struct wlr_surface_state *state = subsurface->surface->current; 156 if (!sway_assert(renderer != NULL,
107 double sx = state->subsurface_position.x; 157 "expected the output backend to have a renderer")) {
108 double sy = state->subsurface_position.y; 158 return;
109 rotate_child_position(&sx, &sy, state->width, state->height,
110 surface->current->width, surface->current->height, rotation);
111
112 render_surface(subsurface->surface, wlr_output, when,
113 ox + sx, oy + sy, rotation, alpha);
114 } 159 }
160
161 scale_box(&box, wlr_output->scale);
162
163 float matrix[9];
164 enum wl_output_transform transform =
165 wlr_output_transform_invert(surface->current->transform);
166 wlr_matrix_project_box(matrix, &box, transform, rotation,
167 wlr_output->transform_matrix);
168
169 wlr_render_texture_with_matrix(renderer, surface->texture,
170 matrix, alpha);
171
172 // TODO: don't send the frame done event now
173 wlr_surface_send_frame_done(surface, when);
115} 174}
116 175
117static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, 176static void render_surface(struct sway_output *output, struct timespec *when,
118 struct wlr_output *wlr_output, struct timespec *when, double base_x, 177 struct wlr_surface *surface, double ox, double oy, float rotation) {
119 double base_y, float rotation, float alpha) { 178 struct render_data data = {
120 double width = surface->surface->current->width; 179 .output = output,
121 double height = surface->surface->current->height; 180 .when = when,
122 181 .alpha = 1.0f,
123 struct wlr_xdg_popup_v6 *popup_state; 182 };
124 wl_list_for_each(popup_state, &surface->popups, link) {
125 struct wlr_xdg_surface_v6 *popup = popup_state->base;
126 if (!popup->configured) {
127 continue;
128 }
129 183
130 double popup_width = popup->surface->current->width; 184 output_surface_for_each_surface(surface, ox, oy, rotation, &data.root_geo,
131 double popup_height = popup->surface->current->height; 185 render_surface_iterator, &data);
186}
132 187
133 double popup_sx, popup_sy; 188static void render_view(struct sway_output *output, struct timespec *when,
134 wlr_xdg_surface_v6_popup_get_position(popup, &popup_sx, &popup_sy); 189 struct sway_view *view) {
135 rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, 190 struct render_data data = {
136 width, height, rotation); 191 .output = output,
192 .when = when,
193 .alpha = view->swayc->alpha,
194 };
137 195
138 render_surface(popup->surface, wlr_output, when, 196 output_view_for_each_surface(view, &data.root_geo,
139 base_x + popup_sx, base_y + popup_sy, rotation, alpha); 197 render_surface_iterator, &data);
140 render_xdg_v6_popups(popup, wlr_output, when,
141 base_x + popup_sx, base_y + popup_sy, rotation, alpha);
142 }
143} 198}
144 199
145static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, 200static void render_layer(struct sway_output *output, struct timespec *when,
146 struct wlr_output *wlr_output, struct timespec *when, 201 struct wl_list *layer_surfaces) {
147 double lx, double ly, float rotation, float alpha, 202 struct sway_layer_surface *layer_surface;
148 bool is_child) { 203 wl_list_for_each(layer_surface, layer_surfaces, link) {
149 if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) { 204 struct wlr_layer_surface *wlr_layer_surface =
150 render_surface(surface->surface, wlr_output, when, 205 layer_surface->layer_surface;
151 lx, ly, rotation, alpha); 206 render_surface(output, when, wlr_layer_surface->surface,
152 207 layer_surface->geo.x, layer_surface->geo.y, 0);
153 double width = surface->surface->current->width;
154 double height = surface->surface->current->height;
155
156 struct wlr_wl_shell_surface *popup;
157 wl_list_for_each(popup, &surface->popups, popup_link) {
158 double popup_width = popup->surface->current->width;
159 double popup_height = popup->surface->current->height;
160
161 double popup_x = popup->transient_state->x;
162 double popup_y = popup->transient_state->y;
163 rotate_child_position(&popup_x, &popup_y, popup_width, popup_height,
164 width, height, rotation);
165
166 render_wl_shell_surface(popup, wlr_output, when,
167 lx + popup_x, ly + popup_y, rotation, alpha, true);
168 }
169 } 208 }
170} 209}
171 210
172struct render_data { 211struct render_view_data {
173 struct sway_output *output; 212 struct sway_output *output;
174 struct timespec *when; 213 struct timespec *when;
175}; 214};
176 215
177static void render_view(struct sway_container *view, void *data) { 216static void render_view_iterator(struct sway_container *con, void *_data) {
178 struct render_data *rdata = data; 217 struct render_view_data *data = _data;
179 struct sway_output *output = rdata->output;
180 struct timespec *when = rdata->when;
181 struct wlr_output *wlr_output = output->wlr_output;
182 struct sway_view *sway_view = view->sway_view;
183 struct wlr_surface *surface = sway_view->surface;
184 float alpha = sway_view->swayc->alpha;
185 218
186 if (!surface) { 219 if (!sway_assert(con->type == C_VIEW, "expected a view")) {
187 return; 220 return;
188 } 221 }
189 222
190 switch (sway_view->type) { 223 render_view(data->output, data->when, con->sway_view);
191 case SWAY_VIEW_XDG_SHELL_V6: {
192 int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry.x;
193 int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry.y;
194 render_surface(surface, wlr_output, when,
195 view->x - window_offset_x, view->y - window_offset_y, 0, alpha);
196 render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output,
197 when, view->x - window_offset_x, view->y - window_offset_y, 0, alpha);
198 break;
199 }
200 case SWAY_VIEW_WL_SHELL:
201 render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output,
202 when, view->x, view->y, 0, alpha, false);
203 break;
204 case SWAY_VIEW_XWAYLAND:
205 render_surface(surface, wlr_output, when, view->x, view->y, 0, alpha);
206 break;
207 }
208}
209
210static void render_layer(struct sway_output *output, struct timespec *when,
211 struct wl_list *layer) {
212 struct sway_layer_surface *sway_layer;
213 wl_list_for_each(sway_layer, layer, link) {
214 struct wlr_layer_surface *layer = sway_layer->layer_surface;
215 render_surface(layer->surface, output->wlr_output, when,
216 sway_layer->geo.x, sway_layer->geo.y, 0, 1.0f);
217 wlr_surface_send_frame_done(layer->surface, when);
218 }
219} 224}
220 225
221static void render_output(struct sway_output *output, struct timespec *when, 226static void render_output(struct sway_output *output, struct timespec *when,
222 pixman_region32_t *damage) { 227 pixman_region32_t *damage) {
223 struct wlr_output *wlr_output = output->wlr_output; 228 struct wlr_output *wlr_output = output->wlr_output;
229
224 struct wlr_renderer *renderer = 230 struct wlr_renderer *renderer =
225 wlr_backend_get_renderer(wlr_output->backend); 231 wlr_backend_get_renderer(wlr_output->backend);
232 if (!sway_assert(renderer != NULL,
233 "expected the output backend to have a renderer")) {
234 return;
235 }
226 236
227 wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); 237 wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
228 238
@@ -231,24 +241,15 @@ static void render_output(struct sway_output *output, struct timespec *when,
231 goto renderer_end; 241 goto renderer_end;
232 } 242 }
233 243
234 // TODO: don't damage the whole output here
235 int width, height;
236 wlr_output_transformed_resolution(wlr_output, &width, &height);
237 pixman_region32_union_rect(damage, damage, 0, 0, width, height);
238
239 float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; 244 float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
240 wlr_renderer_clear(renderer, clear_color); 245 wlr_renderer_clear(renderer, clear_color);
241 246
242 struct wlr_output_layout *output_layout =
243 root_container.sway_root->output_layout;
244 const struct wlr_box *output_box =
245 wlr_output_layout_get_box(output_layout, wlr_output);
246
247 render_layer(output, when, 247 render_layer(output, when,
248 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); 248 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
249 render_layer(output, when, 249 render_layer(output, when,
250 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); 250 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
251 251
252 // Render all views in the current workspace
252 struct sway_seat *seat = input_manager_current_seat(input_manager); 253 struct sway_seat *seat = input_manager_current_seat(input_manager);
253 struct sway_container *focus = 254 struct sway_container *focus =
254 seat_get_focus_inactive(seat, output->swayc); 255 seat_get_focus_inactive(seat, output->swayc);
@@ -258,36 +259,21 @@ static void render_output(struct sway_output *output, struct timespec *when,
258 } 259 }
259 struct sway_container *workspace = focus->type == C_WORKSPACE ? 260 struct sway_container *workspace = focus->type == C_WORKSPACE ?
260 focus : container_parent(focus, C_WORKSPACE); 261 focus : container_parent(focus, C_WORKSPACE);
262 struct render_view_data data = { .output = output, .when = when };
263 container_descendants(workspace, C_VIEW, render_view_iterator, &data);
261 264
262 struct render_data rdata = { 265 // Render unmanaged views on top
263 .output = output,
264 .when = when,
265 };
266 container_descendants(workspace, C_VIEW, render_view, &rdata);
267
268 // render unmanaged views on top
269 struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; 266 struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged;
270 struct sway_xwayland_unmanaged *unmanaged_surface; 267 struct sway_xwayland_unmanaged *unmanaged_surface;
271 wl_list_for_each(unmanaged_surface, unmanaged, link) { 268 wl_list_for_each(unmanaged_surface, unmanaged, link) {
272 struct wlr_xwayland_surface *xsurface = 269 struct wlr_xwayland_surface *xsurface =
273 unmanaged_surface->wlr_xwayland_surface; 270 unmanaged_surface->wlr_xwayland_surface;
274 271 double ox = unmanaged_surface->lx - output->swayc->x;
275 const struct wlr_box view_box = { 272 double oy = unmanaged_surface->ly - output->swayc->y;
276 .x = unmanaged_surface->lx, 273 render_surface(output, when, xsurface->surface, ox, oy, 0);
277 .y = unmanaged_surface->ly,
278 .width = xsurface->width,
279 .height = xsurface->height,
280 };
281 struct wlr_box intersection;
282 if (!wlr_box_intersection(&view_box, output_box, &intersection)) {
283 continue;
284 }
285
286 render_surface(xsurface->surface, wlr_output, &output->last_frame,
287 view_box.x - output_box->x, view_box.y - output_box->y, 0, 1.0f);
288 } 274 }
289 275
290 // TODO: Consider revising this when fullscreen windows are supported 276 // TODO: consider revising this when fullscreen windows are supported
291 render_layer(output, when, 277 render_layer(output, when,
292 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); 278 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
293 render_layer(output, when, 279 render_layer(output, when,