/*
* Copyright © 2013 Keith Packard
* Copyright © 2015 Boyan Ding
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef LOADER_DRI3_HEADER_H
#define LOADER_DRI3_HEADER_H
#include <stdbool.h>
#include <stdint.h>
#include <xcb/xcb.h>
#include <xcb/dri3.h>
#include <xcb/present.h>
#include <GL/gl.h>
#include <GL/internal/dri_interface.h>
#include <c11/threads.h>
enum loader_dri3_buffer_type {
loader_dri3_buffer_back = 0,
loader_dri3_buffer_front = 1
};
struct loader_dri3_buffer {
__DRIimage *image;
__DRIimage *linear_buffer;
uint32_t pixmap;
/* Synchronization between the client and X server is done using an
* xshmfence that is mapped into an X server SyncFence. This lets the
* client check whether the X server is done using a buffer with a simple
* xshmfence call, rather than going to read X events from the wire.
*
* However, we can only wait for one xshmfence to be triggered at a time,
* so we need to know *which* buffer is going to be idle next. We do that
* by waiting for a PresentIdleNotify event. When that event arrives, the
* 'busy' flag gets cleared and the client knows that the fence has been
* triggered, and that the wait call will not block.
*/
uint32_t sync_fence; /* XID of X SyncFence object */
struct xshmfence *shm_fence; /* pointer to xshmfence object */
bool busy; /* Set on swap, cleared on IdleNotify */
bool own_pixmap; /* We allocated the pixmap ID, free on destroy */
uint32_t size;
uint32_t pitch;
uint32_t cpp;
uint32_t flags;
uint32_t width, height;
uint64_t last_swap;
};
#define LOADER_DRI3_MAX_BACK 4
#define LOADER_DRI3_BACK_ID(i) (i)
#define LOADER_DRI3_FRONT_ID (LOADER_DRI3_MAX_BACK)
static inline int
loader_dri3_pixmap_buf_id(enum loader_dri3_buffer_type buffer_type)
{
if (buffer_type == loader_dri3_buffer_back)
return LOADER_DRI3_BACK_ID(0);
else
return LOADER_DRI3_FRONT_ID;
}
struct loader_dri3_extensions {
const __DRIcoreExtension *core;
const __DRIimageDriverExtension *image_driver;
const __DRI2flushExtension *flush;
const __DRI2configQueryExtension *config;
const __DRItexBufferExtension *tex_buffer;
const __DRIimageExtension *image;
};
struct loader_dri3_drawable;
struct loader_dri3_vtable {
void (*set_drawable_size)(struct loader_dri3_drawable *, int, int);
bool (*in_current_context)(struct loader_dri3_drawable *);
__DRIcontext *(*get_dri_context)(struct loader_dri3_drawable *);
__DRIscreen *(*get_dri_screen)(void);
void (*flush_drawable)(struct loader_dri3_drawable *, unsigned);
void (*show_fps)(struct loader_dri3_drawable *, uint64_t);
};
#define LOADER_DRI3_NUM_BUFFERS (1 + LOADER_DRI3_MAX_BACK)
struct loader_dri3_drawable {
xcb_connection_t *conn;
__DRIdrawable *dri_drawable;
xcb_drawable_t drawable;
int width;
int height;
int depth;
uint8_t have_back;
uint8_t have_fake_front;
uint8_t is_pixmap;
uint8_t flipping;
/* Information about the GPU owning the buffer */
__DRIscreen *dri_screen;
bool is_different_gpu;
/* Present extension capabilities
*/
uint32_t present_capabilities;
/* SBC numbers are tracked by using the serial numbers
* in the present request and complete events
*/
uint64_t send_sbc;
uint64_t recv_sbc;
/* Last received UST/MSC values for pixmap present complete */
uint64_t ust, msc;
/* Last received UST/MSC values from present notify msc event */
uint64_t notify_ust, notify_msc;
struct loader_dri3_buffer *buffers[LOADER_DRI3_NUM_BUFFERS];
int cur_back;
int num_back;
int cur_blit_source;
uint32_t *stamp;
xcb_present_event_t eid;
xcb_gcontext_t gc;
xcb_special_event_t *special_event;
bool first_init;
int swap_interval;
struct loader_dri3_extensions *ext;
const struct loader_dri3_vtable *vtable;
unsigned int swap_method;
unsigned int back_format;
/* Currently protects the following fields:
* event_cnd, has_event_waiter,
* recv_sbc, ust, msc, recv_msc_serial,
* notify_ust, notify_msc
*/
mtx_t mtx;
cnd_t event_cnd;
bool has_event_waiter;
};
void
loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw,
int interval);
void
loader_dri3_drawable_fini(struct loader_dri3_drawable *draw);
int
loader_dri3_drawable_init(xcb_connection_t *conn,
xcb_drawable_t drawable,
__DRIscreen *dri_screen,
bool is_different_gpu,
const __DRIconfig *dri_config,
struct loader_dri3_extensions *ext,
const struct loader_dri3_vtable *vtable,
struct loader_dri3_drawable*);
bool loader_dri3_wait_for_msc(struct loader_dri3_drawable *draw,
int64_t target_msc,
int64_t divisor, int64_t remainder,
int64_t *ust, int64_t *msc, int64_t *sbc);
int64_t
loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
int64_t target_msc, int64_t divisor,
int64_t remainder, unsigned flush_flags,
bool force_copy);
int
loader_dri3_wait_for_sbc(struct loader_dri3_drawable *draw,
int64_t target_sbc, int64_t *ust,
int64_t *msc, int64_t *sbc);
int loader_dri3_query_buffer_age(struct loader_dri3_drawable *draw);
void
loader_dri3_flush(struct loader_dri3_drawable *draw,
unsigned flags,
enum __DRI2throttleReason throttle_reason);
void
loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw,
int x, int y,
int width, int height,
bool flush);
void
loader_dri3_copy_drawable(struct loader_dri3_drawable *draw,
xcb_drawable_t dest,
xcb_drawable_t src);
void
loader_dri3_wait_x(struct loader_dri3_drawable *draw);
void
loader_dri3_wait_gl(struct loader_dri3_drawable *draw);
int loader_dri3_open(xcb_connection_t *conn,
xcb_window_t root,
uint32_t provider);
__DRIimage *
loader_dri3_create_image(xcb_connection_t *c,
xcb_dri3_buffer_from_pixmap_reply_t *bp_reply,
unsigned int format,
__DRIscreen *dri_screen,
const __DRIimageExtension *image,
void *loaderPrivate);
int
loader_dri3_get_buffers(__DRIdrawable *driDrawable,
unsigned int format,
uint32_t *stamp,
void *loaderPrivate,
uint32_t buffer_mask,
struct __DRIimageList *buffers);
void
loader_dri3_update_drawable_geometry(struct loader_dri3_drawable *draw);
void
loader_dri3_swapbuffer_barrier(struct loader_dri3_drawable *draw);
void
loader_dri3_close_screen(__DRIscreen *dri_screen);
#endif