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    __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 
82 static inline int
loader_dri3_pixmap_buf_id(enum loader_dri3_buffer_type buffer_type)83 loader_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 
91 struct 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 
100 struct loader_dri3_drawable;
101 
102 struct 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 
113 struct 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 cur_num_back;
150    int max_num_back;
151    int cur_blit_source;
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    bool adaptive_sync;
161    bool adaptive_sync_active;
162    int swap_interval;
163 
164    struct loader_dri3_extensions *ext;
165    const struct loader_dri3_vtable *vtable;
166 
167    unsigned int swap_method;
168    unsigned int back_format;
169    xcb_present_complete_mode_t last_present_mode;
170 
171    bool is_protected_content;
172 
173    /* Currently protects the following fields:
174     * event_cnd, has_event_waiter,
175     * recv_sbc, ust, msc, recv_msc_serial,
176     * notify_ust, notify_msc
177     */
178    mtx_t mtx;
179    cnd_t event_cnd;
180    unsigned last_special_event_sequence;
181    bool has_event_waiter;
182 };
183 
184 void
185 loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw,
186                               int interval);
187 
188 void
189 loader_dri3_drawable_fini(struct loader_dri3_drawable *draw);
190 
191 int
192 loader_dri3_drawable_init(xcb_connection_t *conn,
193                           xcb_drawable_t drawable,
194                           __DRIscreen *dri_screen,
195                           bool is_different_gpu,
196                           bool is_multiplanes_available,
197                           const __DRIconfig *dri_config,
198                           struct loader_dri3_extensions *ext,
199                           const struct loader_dri3_vtable *vtable,
200                           struct loader_dri3_drawable*);
201 
202 bool loader_dri3_wait_for_msc(struct loader_dri3_drawable *draw,
203                               int64_t target_msc,
204                               int64_t divisor, int64_t remainder,
205                               int64_t *ust, int64_t *msc, int64_t *sbc);
206 
207 int64_t
208 loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
209                              int64_t target_msc, int64_t divisor,
210                              int64_t remainder, unsigned flush_flags,
211                              const int *rects, int n_rects,
212                              bool force_copy);
213 
214 int
215 loader_dri3_wait_for_sbc(struct loader_dri3_drawable *draw,
216                          int64_t target_sbc, int64_t *ust,
217                          int64_t *msc, int64_t *sbc);
218 
219 int loader_dri3_query_buffer_age(struct loader_dri3_drawable *draw);
220 
221 void
222 loader_dri3_flush(struct loader_dri3_drawable *draw,
223                   unsigned flags,
224                   enum __DRI2throttleReason throttle_reason);
225 
226 void
227 loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw,
228                             int x, int y,
229                             int width, int height,
230                             bool flush);
231 
232 void
233 loader_dri3_copy_drawable(struct loader_dri3_drawable *draw,
234                           xcb_drawable_t dest,
235                           xcb_drawable_t src);
236 
237 void
238 loader_dri3_wait_x(struct loader_dri3_drawable *draw);
239 
240 void
241 loader_dri3_wait_gl(struct loader_dri3_drawable *draw);
242 
243 int loader_dri3_open(xcb_connection_t *conn,
244                      xcb_window_t root,
245                      uint32_t provider);
246 
247 __DRIimage *
248 loader_dri3_create_image(xcb_connection_t *c,
249                          xcb_dri3_buffer_from_pixmap_reply_t *bp_reply,
250                          unsigned int format,
251                          __DRIscreen *dri_screen,
252                          const __DRIimageExtension *image,
253                          void *loaderPrivate);
254 
255 #ifdef HAVE_DRI3_MODIFIERS
256 __DRIimage *
257 loader_dri3_create_image_from_buffers(xcb_connection_t *c,
258                                       xcb_dri3_buffers_from_pixmap_reply_t *bp_reply,
259                                       unsigned int format,
260                                       __DRIscreen *dri_screen,
261                                       const __DRIimageExtension *image,
262                                       void *loaderPrivate);
263 #endif
264 int
265 loader_dri3_get_buffers(__DRIdrawable *driDrawable,
266                         unsigned int format,
267                         uint32_t *stamp,
268                         void *loaderPrivate,
269                         uint32_t buffer_mask,
270                         struct __DRIimageList *buffers);
271 
272 void
273 loader_dri3_update_drawable_geometry(struct loader_dri3_drawable *draw);
274 
275 void
276 loader_dri3_swapbuffer_barrier(struct loader_dri3_drawable *draw);
277 
278 void
279 loader_dri3_close_screen(__DRIscreen *dri_screen);
280 #endif
281