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
38enum loader_dri3_buffer_type {
39   loader_dri3_buffer_back = 0,
40   loader_dri3_buffer_front = 1
41};
42
43struct 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
88static inline int
89loader_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
97struct 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
106struct loader_dri3_drawable;
107
108struct 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
119struct 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
195void
196loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw,
197                              int interval);
198
199void
200loader_dri3_drawable_fini(struct loader_dri3_drawable *draw);
201
202int
203loader_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
214bool 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
219int64_t
220loader_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
226int
227loader_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
231int loader_dri3_query_buffer_age(struct loader_dri3_drawable *draw);
232
233void
234loader_dri3_flush(struct loader_dri3_drawable *draw,
235                  unsigned flags,
236                  enum __DRI2throttleReason throttle_reason);
237
238void
239loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw,
240                            int x, int y,
241                            int width, int height,
242                            bool flush);
243
244void
245loader_dri3_copy_drawable(struct loader_dri3_drawable *draw,
246                          xcb_drawable_t dest,
247                          xcb_drawable_t src);
248
249void
250loader_dri3_wait_x(struct loader_dri3_drawable *draw);
251
252void
253loader_dri3_wait_gl(struct loader_dri3_drawable *draw);
254
255int loader_dri3_open(xcb_connection_t *conn,
256                     xcb_window_t root,
257                     uint32_t provider);
258
259__DRIimage *
260loader_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 *
269loader_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
276int
277loader_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
284void
285loader_dri3_update_drawable_geometry(struct loader_dri3_drawable *draw);
286
287void
288loader_dri3_swapbuffer_barrier(struct loader_dri3_drawable *draw);
289
290void
291loader_dri3_close_screen(__DRIscreen *dri_screen);
292#endif
293