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
119enum loader_dri3_drawable_type {
120   LOADER_DRI3_DRAWABLE_UNKNOWN,
121   LOADER_DRI3_DRAWABLE_WINDOW,
122   LOADER_DRI3_DRAWABLE_PIXMAP,
123   LOADER_DRI3_DRAWABLE_PBUFFER,
124};
125
126struct loader_dri3_drawable {
127   xcb_connection_t *conn;
128   xcb_screen_t *screen;
129   __DRIdrawable *dri_drawable;
130   xcb_drawable_t drawable;
131   xcb_window_t window;
132   xcb_xfixes_region_t region;
133   int width;
134   int height;
135   int depth;
136   uint8_t have_back;
137   uint8_t have_fake_front;
138   enum loader_dri3_drawable_type type;
139
140   /* Information about the GPU owning the buffer */
141   __DRIscreen *dri_screen;
142   bool is_different_gpu;
143   bool multiplanes_available;
144   bool prefer_back_buffer_reuse;
145
146   /* DRI screen created for display GPU in case of prime */
147   __DRIscreen *dri_screen_display_gpu;
148
149   /* SBC numbers are tracked by using the serial numbers
150    * in the present request and complete events
151    */
152   uint64_t send_sbc;
153   uint64_t recv_sbc;
154
155   /* Last received UST/MSC values for pixmap present complete */
156   uint64_t ust, msc;
157
158   /* Last received UST/MSC values from present notify msc event */
159   uint64_t notify_ust, notify_msc;
160
161   struct loader_dri3_buffer *buffers[LOADER_DRI3_NUM_BUFFERS];
162   int cur_back;
163   int cur_num_back;
164   int max_num_back;
165   int cur_blit_source;
166
167   uint32_t *stamp;
168
169   xcb_present_event_t eid;
170   xcb_gcontext_t gc;
171   xcb_special_event_t *special_event;
172
173   bool first_init;
174   bool adaptive_sync;
175   bool adaptive_sync_active;
176   int swap_interval;
177
178   struct loader_dri3_extensions *ext;
179   const struct loader_dri3_vtable *vtable;
180
181   unsigned int swap_method;
182   unsigned int back_format;
183   xcb_present_complete_mode_t last_present_mode;
184
185   bool is_protected_content;
186
187   /* Currently protects the following fields:
188    * event_cnd, has_event_waiter,
189    * recv_sbc, ust, msc, recv_msc_serial,
190    * notify_ust, notify_msc
191    */
192   mtx_t mtx;
193   cnd_t event_cnd;
194   unsigned last_special_event_sequence;
195   bool has_event_waiter;
196};
197
198void
199loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw,
200                              int interval);
201
202void
203loader_dri3_drawable_fini(struct loader_dri3_drawable *draw);
204
205int
206loader_dri3_drawable_init(xcb_connection_t *conn,
207                          xcb_drawable_t drawable,
208                          enum loader_dri3_drawable_type type,
209                          __DRIscreen *dri_screen,
210                          bool is_different_gpu,
211                          bool is_multiplanes_available,
212                          bool prefer_back_buffer_reuse,
213                          const __DRIconfig *dri_config,
214                          struct loader_dri3_extensions *ext,
215                          const struct loader_dri3_vtable *vtable,
216                          struct loader_dri3_drawable*);
217
218bool loader_dri3_wait_for_msc(struct loader_dri3_drawable *draw,
219                              int64_t target_msc,
220                              int64_t divisor, int64_t remainder,
221                              int64_t *ust, int64_t *msc, int64_t *sbc);
222
223int64_t
224loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
225                             int64_t target_msc, int64_t divisor,
226                             int64_t remainder, unsigned flush_flags,
227                             const int *rects, int n_rects,
228                             bool force_copy);
229
230int
231loader_dri3_wait_for_sbc(struct loader_dri3_drawable *draw,
232                         int64_t target_sbc, int64_t *ust,
233                         int64_t *msc, int64_t *sbc);
234
235int loader_dri3_query_buffer_age(struct loader_dri3_drawable *draw);
236
237void
238loader_dri3_flush(struct loader_dri3_drawable *draw,
239                  unsigned flags,
240                  enum __DRI2throttleReason throttle_reason);
241
242void
243loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw,
244                            int x, int y,
245                            int width, int height,
246                            bool flush);
247
248void
249loader_dri3_copy_drawable(struct loader_dri3_drawable *draw,
250                          xcb_drawable_t dest,
251                          xcb_drawable_t src);
252
253void
254loader_dri3_wait_x(struct loader_dri3_drawable *draw);
255
256void
257loader_dri3_wait_gl(struct loader_dri3_drawable *draw);
258
259int loader_dri3_open(xcb_connection_t *conn,
260                     xcb_window_t root,
261                     uint32_t provider);
262
263__DRIimage *
264loader_dri3_create_image(xcb_connection_t *c,
265                         xcb_dri3_buffer_from_pixmap_reply_t *bp_reply,
266                         unsigned int format,
267                         __DRIscreen *dri_screen,
268                         const __DRIimageExtension *image,
269                         void *loaderPrivate);
270
271#ifdef HAVE_DRI3_MODIFIERS
272__DRIimage *
273loader_dri3_create_image_from_buffers(xcb_connection_t *c,
274                                      xcb_dri3_buffers_from_pixmap_reply_t *bp_reply,
275                                      unsigned int format,
276                                      __DRIscreen *dri_screen,
277                                      const __DRIimageExtension *image,
278                                      void *loaderPrivate);
279#endif
280int
281loader_dri3_get_buffers(__DRIdrawable *driDrawable,
282                        unsigned int format,
283                        uint32_t *stamp,
284                        void *loaderPrivate,
285                        uint32_t buffer_mask,
286                        struct __DRIimageList *buffers);
287
288void
289loader_dri3_update_drawable_geometry(struct loader_dri3_drawable *draw);
290
291void
292loader_dri3_swapbuffer_barrier(struct loader_dri3_drawable *draw);
293
294void
295loader_dri3_close_screen(__DRIscreen *dri_screen);
296#endif
297