1 /*
2 * Copyright © 2013 Keith Packard
3 * Copyright © 2015 Boyan Ding
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting documentation, and
9 * that the name of the copyright holders not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no representations
12 * about the suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 * OF THIS SOFTWARE.
22 */
23
24 #ifndef LOADER_DRI3_HEADER_H
25 #define LOADER_DRI3_HEADER_H
26
27 #include <stdbool.h>
28 #include <stdint.h>
29
30 #include <xcb/xcb.h>
31 #include <xcb/dri3.h>
32 #include <xcb/present.h>
33
34 #include <GL/gl.h>
35 #include <GL/internal/dri_interface.h>
36 #include <c11/threads.h>
37
38 enum loader_dri3_buffer_type {
39 loader_dri3_buffer_back = 0,
40 loader_dri3_buffer_front = 1
41 };
42
43 struct loader_dri3_buffer {
44 __DRIimage *image;
45 uint32_t pixmap;
46
47 /* default case: linear buffer allocated in render gpu vram.
48 * p2p case: linear buffer allocated in display gpu vram and imported
49 * to render gpu. p2p case is enabled when driver name matches
50 * while creating screen in dri3_create_screen() function.
51 */
52 __DRIimage *linear_buffer;
53
54 /* Synchronization between the client and X server is done using an
55 * xshmfence that is mapped into an X server SyncFence. This lets the
56 * client check whether the X server is done using a buffer with a simple
57 * xshmfence call, rather than going to read X events from the wire.
58 *
59 * However, we can only wait for one xshmfence to be triggered at a time,
60 * so we need to know *which* buffer is going to be idle next. We do that
61 * by waiting for a PresentIdleNotify event. When that event arrives, the
62 * 'busy' flag gets cleared and the client knows that the fence has been
63 * triggered, and that the wait call will not block.
64 */
65
66 uint32_t sync_fence; /* XID of X SyncFence object */
67 struct xshmfence *shm_fence; /* pointer to xshmfence object */
68 bool busy; /* Set on swap, cleared on IdleNotify */
69 bool own_pixmap; /* We allocated the pixmap ID, free on destroy */
70 bool reallocate; /* Buffer should be reallocated and not reused */
71
72 uint32_t num_planes;
73 uint32_t size;
74 int strides[4];
75 int offsets[4];
76 uint64_t modifier;
77 uint32_t cpp;
78 uint32_t flags;
79 uint32_t width, height;
80 uint64_t last_swap;
81 };
82
83
84 #define LOADER_DRI3_MAX_BACK 4
85 #define LOADER_DRI3_BACK_ID(i) (i)
86 #define LOADER_DRI3_FRONT_ID (LOADER_DRI3_MAX_BACK)
87
88 static inline int
loader_dri3_pixmap_buf_id(enum loader_dri3_buffer_type buffer_type)89 loader_dri3_pixmap_buf_id(enum loader_dri3_buffer_type buffer_type)
90 {
91 if (buffer_type == loader_dri3_buffer_back)
92 return LOADER_DRI3_BACK_ID(0);
93 else
94 return LOADER_DRI3_FRONT_ID;
95 }
96
97 struct loader_dri3_extensions {
98 const __DRIcoreExtension *core;
99 const __DRIimageDriverExtension *image_driver;
100 const __DRI2flushExtension *flush;
101 const __DRI2configQueryExtension *config;
102 const __DRItexBufferExtension *tex_buffer;
103 const __DRIimageExtension *image;
104 };
105
106 struct loader_dri3_drawable;
107
108 struct loader_dri3_vtable {
109 void (*set_drawable_size)(struct loader_dri3_drawable *, int, int);
110 bool (*in_current_context)(struct loader_dri3_drawable *);
111 __DRIcontext *(*get_dri_context)(struct loader_dri3_drawable *);
112 __DRIscreen *(*get_dri_screen)(void);
113 void (*flush_drawable)(struct loader_dri3_drawable *, unsigned);
114 void (*show_fps)(struct loader_dri3_drawable *, uint64_t);
115 };
116
117 #define LOADER_DRI3_NUM_BUFFERS (1 + LOADER_DRI3_MAX_BACK)
118
119 struct loader_dri3_drawable {
120 xcb_connection_t *conn;
121 xcb_screen_t *screen;
122 __DRIdrawable *dri_drawable;
123 xcb_drawable_t drawable;
124 xcb_window_t window;
125 xcb_xfixes_region_t region;
126 int width;
127 int height;
128 int depth;
129 uint8_t have_back;
130 uint8_t have_fake_front;
131 uint8_t is_pixmap;
132
133 /* Information about the GPU owning the buffer */
134 __DRIscreen *dri_screen;
135 bool is_different_gpu;
136 bool multiplanes_available;
137 bool prefer_back_buffer_reuse;
138
139 /* DRI screen created for display GPU in case of prime */
140 __DRIscreen *dri_screen_display_gpu;
141
142 /* Present extension capabilities
143 */
144 uint32_t present_capabilities;
145
146 /* SBC numbers are tracked by using the serial numbers
147 * in the present request and complete events
148 */
149 uint64_t send_sbc;
150 uint64_t recv_sbc;
151
152 /* Last received UST/MSC values for pixmap present complete */
153 uint64_t ust, msc;
154
155 /* Last received UST/MSC values from present notify msc event */
156 uint64_t notify_ust, notify_msc;
157
158 struct loader_dri3_buffer *buffers[LOADER_DRI3_NUM_BUFFERS];
159 int cur_back;
160 int cur_num_back;
161 int max_num_back;
162 int cur_blit_source;
163
164 uint32_t *stamp;
165
166 xcb_present_event_t eid;
167 xcb_gcontext_t gc;
168 xcb_special_event_t *special_event;
169
170 bool first_init;
171 bool adaptive_sync;
172 bool adaptive_sync_active;
173 int swap_interval;
174
175 struct loader_dri3_extensions *ext;
176 const struct loader_dri3_vtable *vtable;
177
178 unsigned int swap_method;
179 unsigned int back_format;
180 xcb_present_complete_mode_t last_present_mode;
181
182 bool is_protected_content;
183
184 /* Currently protects the following fields:
185 * event_cnd, has_event_waiter,
186 * recv_sbc, ust, msc, recv_msc_serial,
187 * notify_ust, notify_msc
188 */
189 mtx_t mtx;
190 cnd_t event_cnd;
191 unsigned last_special_event_sequence;
192 bool has_event_waiter;
193 };
194
195 void
196 loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw,
197 int interval);
198
199 void
200 loader_dri3_drawable_fini(struct loader_dri3_drawable *draw);
201
202 int
203 loader_dri3_drawable_init(xcb_connection_t *conn,
204 xcb_drawable_t drawable,
205 __DRIscreen *dri_screen,
206 bool is_different_gpu,
207 bool is_multiplanes_available,
208 bool prefer_back_buffer_reuse,
209 const __DRIconfig *dri_config,
210 struct loader_dri3_extensions *ext,
211 const struct loader_dri3_vtable *vtable,
212 struct loader_dri3_drawable*);
213
214 bool loader_dri3_wait_for_msc(struct loader_dri3_drawable *draw,
215 int64_t target_msc,
216 int64_t divisor, int64_t remainder,
217 int64_t *ust, int64_t *msc, int64_t *sbc);
218
219 int64_t
220 loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
221 int64_t target_msc, int64_t divisor,
222 int64_t remainder, unsigned flush_flags,
223 const int *rects, int n_rects,
224 bool force_copy);
225
226 int
227 loader_dri3_wait_for_sbc(struct loader_dri3_drawable *draw,
228 int64_t target_sbc, int64_t *ust,
229 int64_t *msc, int64_t *sbc);
230
231 int loader_dri3_query_buffer_age(struct loader_dri3_drawable *draw);
232
233 void
234 loader_dri3_flush(struct loader_dri3_drawable *draw,
235 unsigned flags,
236 enum __DRI2throttleReason throttle_reason);
237
238 void
239 loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw,
240 int x, int y,
241 int width, int height,
242 bool flush);
243
244 void
245 loader_dri3_copy_drawable(struct loader_dri3_drawable *draw,
246 xcb_drawable_t dest,
247 xcb_drawable_t src);
248
249 void
250 loader_dri3_wait_x(struct loader_dri3_drawable *draw);
251
252 void
253 loader_dri3_wait_gl(struct loader_dri3_drawable *draw);
254
255 int loader_dri3_open(xcb_connection_t *conn,
256 xcb_window_t root,
257 uint32_t provider);
258
259 __DRIimage *
260 loader_dri3_create_image(xcb_connection_t *c,
261 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply,
262 unsigned int format,
263 __DRIscreen *dri_screen,
264 const __DRIimageExtension *image,
265 void *loaderPrivate);
266
267 #ifdef HAVE_DRI3_MODIFIERS
268 __DRIimage *
269 loader_dri3_create_image_from_buffers(xcb_connection_t *c,
270 xcb_dri3_buffers_from_pixmap_reply_t *bp_reply,
271 unsigned int format,
272 __DRIscreen *dri_screen,
273 const __DRIimageExtension *image,
274 void *loaderPrivate);
275 #endif
276 int
277 loader_dri3_get_buffers(__DRIdrawable *driDrawable,
278 unsigned int format,
279 uint32_t *stamp,
280 void *loaderPrivate,
281 uint32_t buffer_mask,
282 struct __DRIimageList *buffers);
283
284 void
285 loader_dri3_update_drawable_geometry(struct loader_dri3_drawable *draw);
286
287 void
288 loader_dri3_swapbuffer_barrier(struct loader_dri3_drawable *draw);
289
290 void
291 loader_dri3_close_screen(__DRIscreen *dri_screen);
292 #endif
293