GCC Code Coverage Report


Directory: ./
File: layer.c
Date: 2025-03-05 16:06:48
Exec Total Coverage
Lines: 169 200 84.5%
Functions: 22 22 100.0%
Branches: 92 126 73.0%

Line Branch Exec Source
1 #include <assert.h>
2 #include <errno.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <xf86drm.h>
6 #include <sys/types.h>
7 #include "private.h"
8
9 struct liftoff_layer *
10 140 liftoff_layer_create(struct liftoff_output *output)
11 {
12 struct liftoff_layer *layer;
13 size_t i;
14
15 140 layer = calloc(1, sizeof(*layer));
16
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→5) taken 140 times.
140 if (layer == NULL) {
17 liftoff_log_errno(LIFTOFF_ERROR, "calloc");
18 return NULL;
19 }
20 140 layer->output = output;
21 140 layer->candidate_planes = calloc(output->device->planes_cap,
22 sizeof(layer->candidate_planes[0]));
23
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→8) taken 140 times.
140 if (layer->candidate_planes == NULL) {
24 liftoff_log_errno(LIFTOFF_ERROR, "calloc");
25 free(layer);
26 return NULL;
27 }
28
2/2
✓ Branch 0 (10→9) taken 1820 times.
✓ Branch 1 (10→11) taken 140 times.
1960 for (i = 0; i < LIFTOFF_PROP_LAST; i++) {
29 1820 layer->core_props[i] = -1;
30 }
31 140 liftoff_list_insert(output->layers.prev, &layer->link);
32 140 output->layers_changed = true;
33 140 return layer;
34 }
35
36 void
37 1 liftoff_layer_destroy(struct liftoff_layer *layer)
38 {
39
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 1 times.
1 if (layer == NULL) {
40 return;
41 }
42
43 1 layer->output->layers_changed = true;
44
1/2
✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→6) taken 1 times.
1 if (layer->plane != NULL) {
45 /* If this layer is displayed on a plane then we need to
46 * free up that plane (to take effect after the next
47 * commit on that CRTC) */
48 struct liftoff_output *output = layer->output;
49 struct liftoff_plane *plane = layer->plane;
50 plane->layer = NULL;
51 plane->free_after_pageflip = output->crtc_id;
52 drmCrtcGetSequence(output->device->drm_fd, output->crtc_id,
53 &plane->free_after_sequence, NULL);
54 }
55
1/2
✗ Branch 0 (6→7) not taken.
✓ Branch 1 (6→8) taken 1 times.
1 if (layer->output->composition_layer == layer) {
56 layer->output->composition_layer = NULL;
57 }
58 1 free(layer->props);
59 1 free(layer->candidate_planes);
60 1 liftoff_list_remove(&layer->link);
61 1 free(layer);
62 }
63
64 struct liftoff_layer_property *
65 43182 layer_get_core_property(struct liftoff_layer *layer, enum liftoff_core_property prop)
66 {
67 ssize_t i;
68
69 43182 i = layer->core_props[prop];
70
2/2
✓ Branch 0 (2→3) taken 12240 times.
✓ Branch 1 (2→4) taken 30942 times.
43182 if (i < 0) {
71 12240 return NULL;
72 }
73 30942 return &layer->props[i];
74 }
75
76 struct liftoff_layer_property *
77 2558 layer_get_property(struct liftoff_layer *layer, const char *name)
78 {
79 ssize_t core_prop_idx;
80 size_t i;
81
82 2558 core_prop_idx = core_property_index(name);
83
2/2
✓ Branch 0 (3→4) taken 2545 times.
✓ Branch 1 (3→6) taken 13 times.
2558 if (core_prop_idx >= 0) {
84 2545 return layer_get_core_property(layer, core_prop_idx);
85 }
86
87
2/2
✓ Branch 0 (10→7) taken 122 times.
✓ Branch 1 (10→11) taken 8 times.
130 for (i = 0; i < layer->props_len; i++) {
88
2/2
✓ Branch 0 (7→8) taken 5 times.
✓ Branch 1 (7→9) taken 117 times.
122 if (strcmp(layer->props[i].name, name) == 0) {
89 5 return &layer->props[i];
90 }
91 }
92 8 return NULL;
93 }
94
95 int
96 2557 liftoff_layer_set_property(struct liftoff_layer *layer, const char *name,
97 uint64_t value)
98 {
99 struct liftoff_layer_property *props;
100 struct liftoff_layer_property *prop;
101 size_t i;
102
103
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→5) taken 2557 times.
2557 if (strcmp(name, "CRTC_ID") == 0) {
104 liftoff_log(LIFTOFF_ERROR,
105 "refusing to set a layer's CRTC_ID");
106 return -EINVAL;
107 }
108
109 2557 prop = layer_get_property(layer, name);
110
2/2
✓ Branch 0 (6→7) taken 1325 times.
✓ Branch 1 (6→14) taken 1232 times.
2557 if (prop == NULL) {
111 1325 props = realloc(layer->props,
112 1325 (layer->props_len + 1) * sizeof(props[0]));
113
1/2
✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→10) taken 1325 times.
1325 if (props == NULL) {
114 liftoff_log_errno(LIFTOFF_ERROR, "realloc");
115 return -ENOMEM;
116 }
117 1325 layer->props = props;
118 1325 layer->props_len++;
119
120 1325 i = layer->props_len - 1;
121 1325 prop = &layer->props[i];
122 1325 *prop = (struct liftoff_layer_property){0};
123 1325 strncpy(prop->name, name, sizeof(prop->name) - 1);
124 1325 prop->core_index = core_property_index(name);
125
126 1325 layer->changed = true;
127
128
2/2
✓ Branch 0 (11→12) taken 1317 times.
✓ Branch 1 (11→13) taken 8 times.
1325 if (prop->core_index >= 0) {
129 1317 layer->core_props[prop->core_index] = (ssize_t)i;
130 }
131 }
132
133 2557 prop->value = value;
134
135
3/4
✓ Branch 0 (14→15) taken 1350 times.
✓ Branch 1 (14→17) taken 1207 times.
✗ Branch 2 (15→16) not taken.
✓ Branch 3 (15→17) taken 1350 times.
2557 if (prop->core_index == LIFTOFF_PROP_FB_ID && layer->force_composition) {
136 layer->force_composition = false;
137 layer->changed = true;
138 }
139
140 2557 return 0;
141 }
142
143 void
144 1 liftoff_layer_unset_property(struct liftoff_layer *layer, const char *name)
145 {
146 struct liftoff_layer_property *prop, *last;
147
148 1 prop = layer_get_property(layer, name);
149
1/2
✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→5) taken 1 times.
1 if (prop == NULL) {
150 return;
151 }
152
153
1/2
✗ Branch 0 (5→6) not taken.
✓ Branch 1 (5→7) taken 1 times.
1 if (prop->core_index >= 0) {
154 layer->core_props[prop->core_index] = -1;
155 }
156
157 1 last = &layer->props[layer->props_len - 1];
158
1/2
✓ Branch 0 (7→8) taken 1 times.
✗ Branch 1 (7→10) not taken.
1 if (prop != last) {
159 1 *prop = *last;
160
1/2
✓ Branch 0 (8→9) taken 1 times.
✗ Branch 1 (8→10) not taken.
1 if (last->core_index >= 0) {
161 1 layer->core_props[last->core_index] = prop - layer->props;
162 }
163 }
164 1 *last = (struct liftoff_layer_property){0};
165 1 layer->props_len--;
166
167 1 layer->changed = true;
168 }
169
170 void
171 1 liftoff_layer_set_fb_composited(struct liftoff_layer *layer)
172 {
173
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 1 times.
1 if (layer->force_composition) {
174 return;
175 }
176
177 1 liftoff_layer_set_property(layer, "FB_ID", 0);
178
179 1 layer->force_composition = true;
180 1 layer->changed = true;
181 }
182
183 struct liftoff_plane *
184 73 liftoff_layer_get_plane(struct liftoff_layer *layer)
185 {
186 73 return layer->plane;
187 }
188
189 bool
190 49 liftoff_layer_needs_composition(struct liftoff_layer *layer)
191 {
192
2/2
✓ Branch 0 (3→4) taken 4 times.
✓ Branch 1 (3→5) taken 45 times.
49 if (!layer_is_visible(layer)) {
193 4 return false;
194 }
195 45 return layer->plane == NULL;
196 }
197
198 void
199 3739 layer_get_rect(struct liftoff_layer *layer, struct liftoff_rect *rect)
200 {
201 struct liftoff_layer_property *x_prop, *y_prop, *w_prop, *h_prop;
202
203 3739 x_prop = layer_get_core_property(layer, LIFTOFF_PROP_CRTC_X);
204 3739 y_prop = layer_get_core_property(layer, LIFTOFF_PROP_CRTC_Y);
205 3739 w_prop = layer_get_core_property(layer, LIFTOFF_PROP_CRTC_W);
206 3739 h_prop = layer_get_core_property(layer, LIFTOFF_PROP_CRTC_H);
207
208
1/2
✓ Branch 0 (6→7) taken 3739 times.
✗ Branch 1 (6→8) not taken.
3739 rect->x = x_prop != NULL ? x_prop->value : 0;
209
1/2
✓ Branch 0 (9→10) taken 3739 times.
✗ Branch 1 (9→11) not taken.
3739 rect->y = y_prop != NULL ? y_prop->value : 0;
210
1/2
✓ Branch 0 (12→13) taken 3739 times.
✗ Branch 1 (12→14) not taken.
3739 rect->width = w_prop != NULL ? w_prop->value : 0;
211
1/2
✓ Branch 0 (15→16) taken 3739 times.
✗ Branch 1 (15→17) not taken.
3739 rect->height = h_prop != NULL ? h_prop->value : 0;
212 3739 }
213
214 void
215 5 layer_get_prev_rect(struct liftoff_layer *layer, struct liftoff_rect *rect)
216 {
217 struct liftoff_layer_property *x_prop, *y_prop, *w_prop, *h_prop;
218
219 5 x_prop = layer_get_core_property(layer, LIFTOFF_PROP_CRTC_X);
220 5 y_prop = layer_get_core_property(layer, LIFTOFF_PROP_CRTC_Y);
221 5 w_prop = layer_get_core_property(layer, LIFTOFF_PROP_CRTC_W);
222 5 h_prop = layer_get_core_property(layer, LIFTOFF_PROP_CRTC_H);
223
224
1/2
✓ Branch 0 (6→7) taken 5 times.
✗ Branch 1 (6→8) not taken.
5 rect->x = x_prop != NULL ? x_prop->prev_value : 0;
225
1/2
✓ Branch 0 (9→10) taken 5 times.
✗ Branch 1 (9→11) not taken.
5 rect->y = y_prop != NULL ? y_prop->prev_value : 0;
226
1/2
✓ Branch 0 (12→13) taken 5 times.
✗ Branch 1 (12→14) not taken.
5 rect->width = w_prop != NULL ? w_prop->prev_value : 0;
227
1/2
✓ Branch 0 (15→16) taken 5 times.
✗ Branch 1 (15→17) not taken.
5 rect->height = h_prop != NULL ? h_prop -> prev_value : 0;
228 5 }
229
230 bool
231 1873 rect_intersects(struct liftoff_rect *ra, struct liftoff_rect *rb)
232 {
233
1/2
✓ Branch 0 (3→4) taken 1839 times.
✗ Branch 1 (3→7) not taken.
1839 return ra->x < rb->x + rb->width && ra->y < rb->y + rb->height &&
234
5/6
✓ Branch 0 (2→3) taken 1839 times.
✓ Branch 1 (2→7) taken 34 times.
✓ Branch 2 (4→5) taken 1809 times.
✓ Branch 3 (4→7) taken 30 times.
✓ Branch 4 (5→6) taken 1809 times.
✗ Branch 5 (5→7) not taken.
3712 ra->x + ra->width > rb->x && ra->y + ra->height > rb->y;
235 }
236
237 bool
238 1875 layer_intersects(struct liftoff_layer *a, struct liftoff_layer *b)
239 {
240 struct liftoff_rect ra, rb;
241
242
3/4
✓ Branch 0 (3→4) taken 1875 times.
✗ Branch 1 (3→6) not taken.
✓ Branch 2 (5→6) taken 8 times.
✓ Branch 3 (5→7) taken 1867 times.
1875 if (!layer_is_visible(a) || !layer_is_visible(b)) {
243 8 return false;
244 }
245
246 1867 layer_get_rect(a, &ra);
247 1867 layer_get_rect(b, &rb);
248
249 1867 return rect_intersects(&ra, &rb);
250 }
251
252 void
253 2600 layer_mark_clean(struct liftoff_layer *layer)
254 {
255 size_t i;
256
257 2600 layer->changed = false;
258 2600 layer->prev_fb_info = layer->fb_info;
259
260
2/2
✓ Branch 0 (4→3) taken 23483 times.
✓ Branch 1 (4→5) taken 2600 times.
26083 for (i = 0; i < layer->props_len; i++) {
261 23483 layer->props[i].prev_value = layer->props[i].value;
262 }
263 2600 }
264
265 static void
266 40 log_priority(struct liftoff_layer *layer)
267 {
268
2/2
✓ Branch 0 (2→3) taken 35 times.
✓ Branch 1 (2→4) taken 5 times.
40 if (layer->current_priority == layer->pending_priority) {
269 35 return;
270 }
271
272 5 liftoff_log(LIFTOFF_DEBUG, "Layer %p priority change: %d -> %d",
273 (void *)layer, layer->current_priority,
274 layer->pending_priority);
275 }
276
277 void
278 2600 layer_update_priority(struct liftoff_layer *layer, bool make_current)
279 {
280 struct liftoff_layer_property *prop;
281
282 /* TODO: also bump priority when updating other properties */
283 2600 prop = layer_get_core_property(layer, LIFTOFF_PROP_FB_ID);
284
4/4
✓ Branch 0 (3→4) taken 2598 times.
✓ Branch 1 (3→6) taken 2 times.
✓ Branch 2 (4→5) taken 1337 times.
✓ Branch 3 (4→6) taken 1261 times.
2600 if (prop != NULL && prop->prev_value != prop->value) {
285 1337 layer->pending_priority++;
286 }
287
288
2/2
✓ Branch 0 (6→7) taken 40 times.
✓ Branch 1 (6→9) taken 2560 times.
2600 if (make_current) {
289 40 log_priority(layer);
290 40 layer->current_priority = layer->pending_priority;
291 40 layer->pending_priority = 0;
292 }
293 2600 }
294
295 bool
296 8158 layer_has_fb(struct liftoff_layer *layer)
297 {
298 struct liftoff_layer_property *fb_id_prop;
299
300 8158 fb_id_prop = layer_get_core_property(layer, LIFTOFF_PROP_FB_ID);
301
4/4
✓ Branch 0 (3→4) taken 8149 times.
✓ Branch 1 (3→6) taken 9 times.
✓ Branch 2 (4→5) taken 8104 times.
✓ Branch 3 (4→6) taken 45 times.
8158 return fb_id_prop != NULL && fb_id_prop->value != 0;
302 }
303
304 bool
305 8083 layer_is_visible(struct liftoff_layer *layer)
306 {
307 struct liftoff_layer_property *alpha_prop;
308
309 8083 alpha_prop = layer_get_core_property(layer, LIFTOFF_PROP_ALPHA);
310
4/4
✓ Branch 0 (3→4) taken 136 times.
✓ Branch 1 (3→6) taken 7947 times.
✓ Branch 2 (4→5) taken 35 times.
✓ Branch 3 (4→6) taken 101 times.
8083 if (alpha_prop != NULL && alpha_prop->value == 0) {
311 35 return false; /* fully transparent */
312 }
313
314
2/2
✓ Branch 0 (6→7) taken 71 times.
✓ Branch 1 (6→8) taken 7977 times.
8048 if (layer->force_composition) {
315 71 return true;
316 } else {
317 7977 return layer_has_fb(layer);
318 }
319 }
320
321 int
322 2600 layer_cache_fb_info(struct liftoff_layer *layer)
323 {
324 struct liftoff_layer_property *fb_id_prop;
325 drmModeFB2 *fb_info;
326 size_t i, j, num_planes;
327 int ret;
328
329 2600 fb_id_prop = layer_get_core_property(layer, LIFTOFF_PROP_FB_ID);
330
4/4
✓ Branch 0 (3→4) taken 2598 times.
✓ Branch 1 (3→5) taken 2 times.
✓ Branch 2 (4→5) taken 5 times.
✓ Branch 3 (4→6) taken 2593 times.
2600 if (fb_id_prop == NULL || fb_id_prop->value == 0) {
331 7 layer->fb_info = (drmModeFB2){0};
332 7 return 0;
333 }
334
335
1/2
✗ Branch 0 (6→7) not taken.
✓ Branch 1 (6→8) taken 2593 times.
2593 if (layer->fb_info.fb_id == fb_id_prop->value) {
336 return 0;
337 }
338
339 2593 fb_info = drmModeGetFB2(layer->output->device->drm_fd, fb_id_prop->value);
340
2/2
✓ Branch 0 (9→10) taken 2587 times.
✓ Branch 1 (9→13) taken 6 times.
2593 if (fb_info == NULL) {
341
1/2
✓ Branch 0 (10→11) taken 2587 times.
✗ Branch 1 (10→12) not taken.
2587 if (errno == EINVAL) {
342 2587 return 0; /* old kernel */
343 }
344 return -errno;
345 }
346
347 /* drmModeGetFB2() always creates new GEM handles -- close these, we
348 * won't use them and we don't want to leak them */
349 6 num_planes = sizeof(fb_info->handles) / sizeof(fb_info->handles[0]);
350
2/2
✓ Branch 0 (27→14) taken 24 times.
✓ Branch 1 (27→28) taken 6 times.
30 for (i = 0; i < num_planes; i++) {
351
1/2
✓ Branch 0 (14→15) taken 24 times.
✗ Branch 1 (14→16) not taken.
24 if (fb_info->handles[i] == 0) {
352 24 continue;
353 }
354
355 ret = drmCloseBufferHandle(layer->output->device->drm_fd,
356 fb_info->handles[i]);
357 if (ret != 0) {
358 liftoff_log_errno(LIFTOFF_ERROR, "drmCloseBufferHandle");
359 continue;
360 }
361
362 /* Make sure we don't double-close a handle */
363 for (j = i + 1; j < num_planes; j++) {
364 if (fb_info->handles[j] == fb_info->handles[i]) {
365 fb_info->handles[j] = 0;
366 }
367 }
368 fb_info->handles[i] = 0;
369 }
370
371 6 layer->fb_info = *fb_info;
372 6 drmModeFreeFB2(fb_info);
373 6 return 0;
374 }
375
376 bool
377 2 liftoff_layer_is_candidate_plane(struct liftoff_layer *layer,
378 struct liftoff_plane *plane)
379 {
380 size_t i;
381
382
2/2
✓ Branch 0 (6→3) taken 3 times.
✓ Branch 1 (6→7) taken 1 times.
4 for (i = 0; i < layer->output->device->planes_cap; i++) {
383
2/2
✓ Branch 0 (3→4) taken 1 times.
✓ Branch 1 (3→5) taken 2 times.
3 if (layer->candidate_planes[i] == plane->id) {
384 1 return true;
385 }
386 }
387
388 1 return false;
389 }
390
391 void
392 333 layer_add_candidate_plane(struct liftoff_layer *layer,
393 struct liftoff_plane *plane)
394 {
395 size_t i;
396 333 ssize_t empty_slot = -1;
397
398
2/2
✓ Branch 0 (9→3) taken 911 times.
✓ Branch 1 (9→10) taken 298 times.
1209 for (i = 0; i < layer->output->device->planes_cap; i++) {
399
2/2
✓ Branch 0 (3→4) taken 35 times.
✓ Branch 1 (3→5) taken 876 times.
911 if (layer->candidate_planes[i] == plane->id) {
400 35 return;
401 }
402
4/4
✓ Branch 0 (5→6) taken 504 times.
✓ Branch 1 (5→8) taken 372 times.
✓ Branch 2 (6→7) taken 298 times.
✓ Branch 3 (6→8) taken 206 times.
876 if (empty_slot < 0 && layer->candidate_planes[i] == 0) {
403 298 empty_slot = (ssize_t)i;
404 }
405 }
406
407
1/2
✗ Branch 0 (10→11) not taken.
✓ Branch 1 (10→12) taken 298 times.
298 assert(empty_slot >= 0);
408 298 layer->candidate_planes[empty_slot] = plane->id;
409 }
410
411 void
412 186 layer_reset_candidate_planes(struct liftoff_layer *layer)
413 {
414 186 memset(layer->candidate_planes, 0,
415 186 sizeof(layer->candidate_planes[0]) * layer->output->device->planes_cap);
416 186 }
417