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
37enum loader_dri3_buffer_type {
38   loader_dri3_buffer_back = 0,
39   loader_dri3_buffer_front = 1
40};
41
42struct loader_dri3_buffer {
43   __DRIimage   *image;
44   __DRIimage   *linear_buffer;
45   uint32_t     pixmap;
46
47   /* Synchronization between the client and X server is done using an
48    * xshmfence that is mapped into an X server SyncFence. This lets the
49    * client check whether the X server is done using a buffer with a simple
50    * xshmfence call, rather than going to read X events from the wire.
51    *
52    * However, we can only wait for one xshmfence to be triggered at a time,
53    * so we need to know *which* buffer is going to be idle next. We do that
54    * by waiting for a PresentIdleNotify event. When that event arrives, the
55    * 'busy' flag gets cleared and the client knows that the fence has been
56    * triggered, and that the wait call will not block.
57    */
58
59   uint32_t     sync_fence;     /* XID of X SyncFence object */
60   struct xshmfence *shm_fence; /* pointer to xshmfence object */
61   bool         busy;           /* Set on swap, cleared on IdleNotify */
62   bool         own_pixmap;     /* We allocated the pixmap ID, free on destroy */
63
64   uint32_t     size;
65   uint32_t     pitch;
66   uint32_t     cpp;
67   uint32_t     flags;
68   uint32_t     width, height;
69   uint64_t     last_swap;
70
71   enum loader_dri3_buffer_type        buffer_type;
72};
73
74
75#define LOADER_DRI3_MAX_BACK   4
76#define LOADER_DRI3_BACK_ID(i) (i)
77#define LOADER_DRI3_FRONT_ID   (LOADER_DRI3_MAX_BACK)
78
79static inline int
80loader_dri3_pixmap_buf_id(enum loader_dri3_buffer_type buffer_type)
81{
82   if (buffer_type == loader_dri3_buffer_back)
83      return LOADER_DRI3_BACK_ID(0);
84   else
85      return LOADER_DRI3_FRONT_ID;
86}
87
88struct loader_dri3_extensions {
89   const __DRIcoreExtension *core;
90   const __DRIimageDriverExtension *image_driver;
91   const __DRI2flushExtension *flush;
92   const __DRI2configQueryExtension *config;
93   const __DRItexBufferExtension *tex_buffer;
94   const __DRIimageExtension *image;
95};
96
97struct loader_dri3_drawable;
98
99struct loader_dri3_vtable {
100   int (*get_swap_interval)(struct loader_dri3_drawable *);
101   int (*clamp_swap_interval)(struct loader_dri3_drawable *, int);
102   void (*set_swap_interval)(struct loader_dri3_drawable *, int);
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)(struct loader_dri3_drawable *);
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   __DRIdrawable *dri_drawable;
116   xcb_drawable_t drawable;
117   int width;
118   int height;
119   int depth;
120   uint8_t have_back;
121   uint8_t have_fake_front;
122   uint8_t is_pixmap;
123   uint8_t flipping;
124
125   /* Information about the GPU owning the buffer */
126   __DRIscreen *dri_screen;
127   bool is_different_gpu;
128
129   /* Present extension capabilities
130    */
131   uint32_t present_capabilities;
132
133   /* SBC numbers are tracked by using the serial numbers
134    * in the present request and complete events
135    */
136   uint64_t send_sbc;
137   uint64_t recv_sbc;
138
139   /* Last received UST/MSC values for pixmap present complete */
140   uint64_t ust, msc;
141
142   /* Last received UST/MSC values from present notify msc event */
143   uint64_t notify_ust, notify_msc;
144
145   /* Serial numbers for tracking wait_for_msc events */
146   uint32_t send_msc_serial;
147   uint32_t recv_msc_serial;
148
149   struct loader_dri3_buffer *buffers[LOADER_DRI3_NUM_BUFFERS];
150   int cur_back;
151   int num_back;
152
153   uint32_t *stamp;
154
155   xcb_present_event_t eid;
156   xcb_gcontext_t gc;
157   xcb_special_event_t *special_event;
158
159   bool first_init;
160
161   struct loader_dri3_extensions *ext;
162   const struct loader_dri3_vtable *vtable;
163};
164
165void
166loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw,
167                              int interval);
168
169void
170loader_dri3_drawable_fini(struct loader_dri3_drawable *draw);
171
172int
173loader_dri3_drawable_init(xcb_connection_t *conn,
174                          xcb_drawable_t drawable,
175                          __DRIscreen *dri_screen,
176                          bool is_different_gpu,
177                          const __DRIconfig *dri_config,
178                          struct loader_dri3_extensions *ext,
179                          const struct loader_dri3_vtable *vtable,
180                          struct loader_dri3_drawable*);
181
182bool loader_dri3_wait_for_msc(struct loader_dri3_drawable *draw,
183                              int64_t target_msc,
184                              int64_t divisor, int64_t remainder,
185                              int64_t *ust, int64_t *msc, int64_t *sbc);
186
187int64_t
188loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
189                             int64_t target_msc, int64_t divisor,
190                             int64_t remainder, unsigned flush_flags,
191                             bool force_copy);
192
193int
194loader_dri3_wait_for_sbc(struct loader_dri3_drawable *draw,
195                         int64_t target_sbc, int64_t *ust,
196                         int64_t *msc, int64_t *sbc);
197
198int loader_dri3_query_buffer_age(struct loader_dri3_drawable *draw);
199
200void
201loader_dri3_flush(struct loader_dri3_drawable *draw,
202                  unsigned flags,
203                  enum __DRI2throttleReason throttle_reason);
204
205void
206loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw,
207                            int x, int y,
208                            int width, int height,
209                            bool flush);
210
211void
212loader_dri3_copy_drawable(struct loader_dri3_drawable *draw,
213                          xcb_drawable_t dest,
214                          xcb_drawable_t src);
215
216void
217loader_dri3_wait_x(struct loader_dri3_drawable *draw);
218
219void
220loader_dri3_wait_gl(struct loader_dri3_drawable *draw);
221
222int loader_dri3_open(xcb_connection_t *conn,
223                     xcb_window_t root,
224                     uint32_t provider);
225
226__DRIimage *
227loader_dri3_create_image(xcb_connection_t *c,
228                         xcb_dri3_buffer_from_pixmap_reply_t *bp_reply,
229                         unsigned int format,
230                         __DRIscreen *dri_screen,
231                         const __DRIimageExtension *image,
232                         void *loaderPrivate);
233
234int
235loader_dri3_get_buffers(__DRIdrawable *driDrawable,
236                        unsigned int format,
237                        uint32_t *stamp,
238                        void *loaderPrivate,
239                        uint32_t buffer_mask,
240                        struct __DRIimageList *buffers);
241
242void
243loader_dri3_update_drawable_geometry(struct loader_dri3_drawable *draw);
244#endif
245