]>
Commit | Line | Data |
---|---|---|
5eef597e MP |
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
2 | ||
3 | /*** | |
4 | This file is part of systemd. | |
5 | ||
6 | Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com> | |
7 | ||
8 | systemd is free software; you can redistribute it and/or modify it | |
9 | under the terms of the GNU Lesser General Public License as published by | |
10 | the Free Software Foundation; either version 2.1 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | systemd is distributed in the hope that it will be useful, but | |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | Lesser General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU Lesser General Public License | |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
20 | ***/ | |
21 | ||
22 | /* | |
23 | * Graphics Devices | |
24 | * The grdev layer provides generic access to graphics devices. The device | |
25 | * types are hidden in the implementation and exported in a generic way. The | |
26 | * grdev_session object forms the base layer. It loads, configures and prepares | |
27 | * any graphics devices associated with that session. Each session is totally | |
28 | * independent of other sessions and can be controlled separately. | |
29 | * The target devices on a session are called display. A display always | |
30 | * corresponds to a real display regardless how many pipes are needed to drive | |
31 | * that display. That is, an exported display might internally be created out | |
32 | * of arbitrary combinations of target pipes. However, this is meant as | |
33 | * implementation detail and API users must never assume details below the | |
34 | * display-level. That is, a display is the most low-level object exported. | |
35 | * Therefore, pipe-configuration and any low-level modesetting is hidden from | |
36 | * the public API. It is provided by the implementation, and it is the | |
37 | * implementation that decides how pipes are driven. | |
38 | * | |
39 | * The API users are free to ignore specific displays or combine them to create | |
40 | * larger screens. This often requires user-configuration so is dictated by | |
41 | * policy. The underlying pipe-configuration might be affected by these | |
42 | * high-level policies, but is never directly controlled by those. That means, | |
43 | * depending on the displays you use, it might affect how underlying resources | |
44 | * are assigned. However, users can never directly apply policies to the pipes, | |
45 | * but only to displays. In case specific hardware needs quirks on the pipe | |
46 | * level, we support that via hwdb, not via public user configuration. | |
47 | * | |
48 | * Right now, displays are limited to rgb32 memory-mapped framebuffers on the | |
49 | * primary plane. However, the grdev implementation can be easily extended to | |
50 | * allow more powerful access (including hardware-acceleration for 2D and 3D | |
51 | * compositing). So far, this wasn't needed so it is not exposed. | |
52 | */ | |
53 | ||
54 | #pragma once | |
55 | ||
5eef597e MP |
56 | #include <libudev.h> |
57 | #include <stdbool.h> | |
58 | #include <stdlib.h> | |
59 | #include <systemd/sd-bus.h> | |
60 | #include <systemd/sd-event.h> | |
61 | #include "util.h" | |
62 | ||
63 | typedef struct grdev_fb grdev_fb; | |
64 | typedef struct grdev_display_target grdev_display_target; | |
65 | typedef struct grdev_display grdev_display; | |
66 | ||
67 | typedef struct grdev_event grdev_event; | |
68 | typedef struct grdev_session grdev_session; | |
69 | typedef struct grdev_context grdev_context; | |
70 | ||
71 | enum { | |
72 | /* clockwise rotation; we treat this is abelian group Z4 with ADD */ | |
73 | GRDEV_ROTATE_0 = 0, | |
74 | GRDEV_ROTATE_90 = 1, | |
75 | GRDEV_ROTATE_180 = 2, | |
76 | GRDEV_ROTATE_270 = 3, | |
77 | }; | |
78 | ||
79 | enum { | |
80 | /* flip states; we treat this as abelian group V4 with XOR */ | |
81 | GRDEV_FLIP_NONE = 0x0, | |
82 | GRDEV_FLIP_HORIZONTAL = 0x1, | |
83 | GRDEV_FLIP_VERTICAL = 0x2, | |
84 | }; | |
85 | ||
86 | /* | |
87 | * Displays | |
88 | */ | |
89 | ||
90 | struct grdev_fb { | |
91 | uint32_t width; | |
92 | uint32_t height; | |
93 | uint32_t format; | |
94 | int32_t strides[4]; | |
95 | void *maps[4]; | |
96 | ||
97 | union { | |
98 | void *ptr; | |
99 | uint64_t u64; | |
100 | } data; | |
101 | ||
102 | void (*free_fn) (void *ptr); | |
103 | }; | |
104 | ||
105 | struct grdev_display_target { | |
106 | uint32_t x; | |
107 | uint32_t y; | |
108 | uint32_t width; | |
109 | uint32_t height; | |
110 | unsigned int rotate; | |
111 | unsigned int flip; | |
112 | grdev_fb *front; | |
113 | grdev_fb *back; | |
114 | }; | |
115 | ||
116 | void grdev_display_set_userdata(grdev_display *display, void *userdata); | |
117 | void *grdev_display_get_userdata(grdev_display *display); | |
118 | ||
119 | const char *grdev_display_get_name(grdev_display *display); | |
120 | uint32_t grdev_display_get_width(grdev_display *display); | |
121 | uint32_t grdev_display_get_height(grdev_display *display); | |
122 | ||
123 | bool grdev_display_is_enabled(grdev_display *display); | |
124 | void grdev_display_enable(grdev_display *display); | |
125 | void grdev_display_disable(grdev_display *display); | |
126 | ||
127 | const grdev_display_target *grdev_display_next_target(grdev_display *display, const grdev_display_target *prev); | |
128 | void grdev_display_flip_target(grdev_display *display, const grdev_display_target *target); | |
129 | ||
130 | #define GRDEV_DISPLAY_FOREACH_TARGET(_display, _t) \ | |
131 | for ((_t) = grdev_display_next_target((_display), NULL); \ | |
132 | (_t); \ | |
133 | (_t) = grdev_display_next_target((_display), (_t))) | |
134 | ||
135 | /* | |
136 | * Events | |
137 | */ | |
138 | ||
139 | enum { | |
140 | GRDEV_EVENT_DISPLAY_ADD, | |
141 | GRDEV_EVENT_DISPLAY_REMOVE, | |
142 | GRDEV_EVENT_DISPLAY_CHANGE, | |
143 | GRDEV_EVENT_DISPLAY_FRAME, | |
144 | }; | |
145 | ||
146 | typedef void (*grdev_event_fn) (grdev_session *session, void *userdata, grdev_event *ev); | |
147 | ||
148 | struct grdev_event { | |
149 | unsigned int type; | |
150 | union { | |
151 | struct { | |
152 | grdev_display *display; | |
153 | } display_add, display_remove, display_change; | |
154 | ||
155 | struct { | |
156 | grdev_display *display; | |
157 | } display_frame; | |
158 | }; | |
159 | }; | |
160 | ||
161 | /* | |
162 | * Sessions | |
163 | */ | |
164 | ||
165 | enum { | |
166 | GRDEV_SESSION_CUSTOM = (1 << 0), | |
167 | GRDEV_SESSION_MANAGED = (1 << 1), | |
168 | }; | |
169 | ||
170 | int grdev_session_new(grdev_session **out, | |
171 | grdev_context *context, | |
172 | unsigned int flags, | |
173 | const char *name, | |
174 | grdev_event_fn event_fn, | |
175 | void *userdata); | |
176 | grdev_session *grdev_session_free(grdev_session *session); | |
177 | ||
178 | DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_session*, grdev_session_free); | |
179 | ||
180 | bool grdev_session_is_enabled(grdev_session *session); | |
181 | void grdev_session_enable(grdev_session *session); | |
182 | void grdev_session_disable(grdev_session *session); | |
183 | ||
184 | void grdev_session_commit(grdev_session *session); | |
185 | void grdev_session_restore(grdev_session *session); | |
186 | ||
187 | void grdev_session_add_drm(grdev_session *session, struct udev_device *ud); | |
188 | void grdev_session_remove_drm(grdev_session *session, struct udev_device *ud); | |
189 | void grdev_session_hotplug_drm(grdev_session *session, struct udev_device *ud); | |
190 | ||
191 | /* | |
192 | * Contexts | |
193 | */ | |
194 | ||
195 | int grdev_context_new(grdev_context **out, sd_event *event, sd_bus *sysbus); | |
196 | grdev_context *grdev_context_ref(grdev_context *context); | |
197 | grdev_context *grdev_context_unref(grdev_context *context); | |
198 | ||
199 | DEFINE_TRIVIAL_CLEANUP_FUNC(grdev_context*, grdev_context_unref); |