GCC Code Coverage Report


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