loader_dri3_helper.h revision 9f464c52
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   __DRIimage   *linear_buffer;
46   uint32_t     pixmap;
47
48   /* Synchronization between the client and X server is done using an
49    * xshmfence that is mapped into an X server SyncFence. This lets the
50    * client check whether the X server is done using a buffer with a simple
51    * xshmfence call, rather than going to read X events from the wire.
52    *
53    * However, we can only wait for one xshmfence to be triggered at a time,
54    * so we need to know *which* buffer is going to be idle next. We do that
55    * by waiting for a PresentIdleNotify event. When that event arrives, the
56    * 'busy' flag gets cleared and the client knows that the fence has been
57    * triggered, and that the wait call will not block.
58    */
59
60   uint32_t     sync_fence;     /* XID of X SyncFence object */
61   struct xshmfence *shm_fence; /* pointer to xshmfence object */
62   bool         busy;           /* Set on swap, cleared on IdleNotify */
63   bool         own_pixmap;     /* We allocated the pixmap ID, free on destroy */
64   bool         reallocate;     /* Buffer should be reallocated and not reused */
65
66   uint32_t     num_planes;
67   uint32_t     size;
68   int          strides[4];
69   int          offsets[4];
70   uint64_t     modifier;
71   uint32_t     cpp;
72   uint32_t     flags;
73   uint32_t     width, height;
74   uint64_t     last_swap;
75};
76
77
78#define LOADER_DRI3_MAX_BACK   4
79#define LOADER_DRI3_BACK_ID(i) (i)
80#define LOADER_DRI3_FRONT_ID   (LOADER_DRI3_MAX_BACK)
81
82static inline int
83loader_dri3_pixmap_buf_id(enum loader_dri3_buffer_type buffer_type)
84{
85   if (buffer_type == loader_dri3_buffer_back)
86      return LOADER_DRI3_BACK_ID(0);
87   else
88      return LOADER_DRI3_FRONT_ID;
89}
90
91struct loader_dri3_extensions {
92   const __DRIcoreExtension *core;
93   const __DRIimageDriverExtension *image_driver;
94   const __DRI2flushExtension *flush;
95   const __DRI2configQueryExtension *config;
96   const __DRItexBufferExtension *tex_buffer;
97   const __DRIimageExtension *image;
98};
99
100struct loader_dri3_drawable;
101
102struct loader_dri3_vtable {
103   void (*set_drawable_size)(struct loader_dri3_drawable *, int, int);
104   bool (*in_current_context)(struct loader_dri3_drawable *);
105   __DRIcontext *(*get_dri_context)(struct loader_dri3_drawable *);
106   __DRIscreen *(*get_dri_screen)(void);
107   void (*flush_drawable)(struct loader_dri3_drawable *, unsigned);
108   void (*show_fps)(struct loader_dri3_drawable *, uint64_t);
109};
110
111#define LOADER_DRI3_NUM_BUFFERS (1 + LOADER_DRI3_MAX_BACK)
112
113struct loader_dri3_drawable {
114   xcb_connection_t *conn;
115   xcb_screen_t *screen;
116   __DRIdrawable *dri_drawable;
117   xcb_drawable_t drawable;
118   xcb_window_t window;
119   int width;
120   int height;
121   int depth;
122   uint8_t have_back;
123   uint8_t have_fake_front;
124   uint8_t is_pixmap;
125
126   /* Information about the GPU owning the buffer */
127   __DRIscreen *dri_screen;
128   bool is_different_gpu;
129   bool multiplanes_available;
130
131   /* Present extension capabilities
132    */
133   uint32_t present_capabilities;
134
135   /* SBC numbers are tracked by using the serial numbers
136    * in the present request and complete events
137    */
138   uint64_t send_sbc;
139   uint64_t recv_sbc;
140
141   /* Last received UST/MSC values for pixmap present complete */
142   uint64_t ust, msc;
143
144   /* Last received UST/MSC values from present notify msc event */
145   uint64_t notify_ust, notify_msc;
146
147   struct loader_dri3_buffer *buffers[LOADER_DRI3_NUM_BUFFERS];
148   int cur_back;
149   int num_back;
150   int cur_blit_source;
151
152   uint32_t *stamp;
153
154   xcb_present_event_t eid;
155   xcb_gcontext_t gc;
156   xcb_special_event_t *special_event;
157
158   bool first_init;
159   bool adaptive_sync;
160   bool adaptive_sync_active;
161   int swap_interval;
162
163   struct loader_dri3_extensions *ext;
164   const struct loader_dri3_vtable *vtable;
165
166   unsigned int swap_method;
167   unsigned int back_format;
168   xcb_present_complete_mode_t last_present_mode;
169
170   /* Currently protects the following fields:
171    * event_cnd, has_event_waiter,
172    * recv_sbc, ust, msc, recv_msc_serial,
173    * notify_ust, notify_msc
174    */
175   mtx_t mtx;
176   cnd_t event_cnd;
177   bool has_event_waiter;
178};
179
180void
181loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw,
182                              int interval);
183
184void
185loader_dri3_drawable_fini(struct loader_dri3_drawable *draw);
186
187int
188loader_dri3_drawable_init(xcb_connection_t *conn,
189                          xcb_drawable_t drawable,
190                          __DRIscreen *dri_screen,
191                          bool is_different_gpu,
192                          bool is_multiplanes_available,
193                          const __DRIconfig *dri_config,
194                          struct loader_dri3_extensions *ext,
195                          const struct loader_dri3_vtable *vtable,
196                          struct loader_dri3_drawable*);
197
198bool loader_dri3_wait_for_msc(struct loader_dri3_drawable *draw,
199                              int64_t target_msc,
200                              int64_t divisor, int64_t remainder,
201                              int64_t *ust, int64_t *msc, int64_t *sbc);
202
203int64_t
204loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
205                             int64_t target_msc, int64_t divisor,
206                             int64_t remainder, unsigned flush_flags,
207                             bool force_copy);
208
209int
210loader_dri3_wait_for_sbc(struct loader_dri3_drawable *draw,
211                         int64_t target_sbc, int64_t *ust,
212                         int64_t *msc, int64_t *sbc);
213
214int loader_dri3_query_buffer_age(struct loader_dri3_drawable *draw);
215
216void
217loader_dri3_flush(struct loader_dri3_drawable *draw,
218                  unsigned flags,
219                  enum __DRI2throttleReason throttle_reason);
220
221void
222loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw,
223                            int x, int y,
224                            int width, int height,
225                            bool flush);
226
227void
228loader_dri3_copy_drawable(struct loader_dri3_drawable *draw,
229                          xcb_drawable_t dest,
230                          xcb_drawable_t src);
231
232void
233loader_dri3_wait_x(struct loader_dri3_drawable *draw);
234
235void
236loader_dri3_wait_gl(struct loader_dri3_drawable *draw);
237
238int loader_dri3_open(xcb_connection_t *conn,
239                     xcb_window_t root,
240                     uint32_t provider);
241
242__DRIimage *
243loader_dri3_create_image(xcb_connection_t *c,
244                         xcb_dri3_buffer_from_pixmap_reply_t *bp_reply,
245                         unsigned int format,
246                         __DRIscreen *dri_screen,
247                         const __DRIimageExtension *image,
248                         void *loaderPrivate);
249
250#ifdef HAVE_DRI3_MODIFIERS
251__DRIimage *
252loader_dri3_create_image_from_buffers(xcb_connection_t *c,
253                                      xcb_dri3_buffers_from_pixmap_reply_t *bp_reply,
254                                      unsigned int format,
255                                      __DRIscreen *dri_screen,
256                                      const __DRIimageExtension *image,
257                                      void *loaderPrivate);
258#endif
259int
260loader_dri3_get_buffers(__DRIdrawable *driDrawable,
261                        unsigned int format,
262                        uint32_t *stamp,
263                        void *loaderPrivate,
264                        uint32_t buffer_mask,
265                        struct __DRIimageList *buffers);
266
267void
268loader_dri3_update_drawable_geometry(struct loader_dri3_drawable *draw);
269
270void
271loader_dri3_swapbuffer_barrier(struct loader_dri3_drawable *draw);
272
273void
274loader_dri3_close_screen(__DRIscreen *dri_screen);
275#endif
276