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