present: Add Present extension
Provides both a software implementation using timers and driver hooks to base everything on vblank intervals. Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
parent
5631382988
commit
5c5c1b7798
|
@ -21,6 +21,10 @@ if DRI3
|
||||||
DRI3_DIR=dri3
|
DRI3_DIR=dri3
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if PRESENT
|
||||||
|
PRESENT_DIR=present
|
||||||
|
endif
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
doc \
|
doc \
|
||||||
man \
|
man \
|
||||||
|
@ -42,6 +46,7 @@ SUBDIRS = \
|
||||||
damageext \
|
damageext \
|
||||||
$(COMPOSITE_DIR) \
|
$(COMPOSITE_DIR) \
|
||||||
$(GLX_DIR) \
|
$(GLX_DIR) \
|
||||||
|
$(PRESENT_DIR) \
|
||||||
$(DRI3_DIR) \
|
$(DRI3_DIR) \
|
||||||
exa \
|
exa \
|
||||||
config \
|
config \
|
||||||
|
|
23
configure.ac
23
configure.ac
|
@ -614,6 +614,7 @@ AC_ARG_ENABLE(glx, AS_HELP_STRING([--disable-glx], [Build GLX extensi
|
||||||
AC_ARG_ENABLE(dri, AS_HELP_STRING([--enable-dri], [Build DRI extension (default: auto)]), [DRI=$enableval])
|
AC_ARG_ENABLE(dri, AS_HELP_STRING([--enable-dri], [Build DRI extension (default: auto)]), [DRI=$enableval])
|
||||||
AC_ARG_ENABLE(dri2, AS_HELP_STRING([--enable-dri2], [Build DRI2 extension (default: auto)]), [DRI2=$enableval], [DRI2=auto])
|
AC_ARG_ENABLE(dri2, AS_HELP_STRING([--enable-dri2], [Build DRI2 extension (default: auto)]), [DRI2=$enableval], [DRI2=auto])
|
||||||
AC_ARG_ENABLE(dri3, AS_HELP_STRING([--enable-dri3], [Build DRI3 extension (default: auto)]), [DRI3=$enableval], [DRI3=auto])
|
AC_ARG_ENABLE(dri3, AS_HELP_STRING([--enable-dri3], [Build DRI3 extension (default: auto)]), [DRI3=$enableval], [DRI3=auto])
|
||||||
|
AC_ARG_ENABLE(present, AS_HELP_STRING([--disable-present], [Build Present extension (default: enabled)]), [PRESENT=$enableval], [PRESENT=yes])
|
||||||
AC_ARG_ENABLE(xinerama, AS_HELP_STRING([--disable-xinerama], [Build Xinerama extension (default: enabled)]), [XINERAMA=$enableval], [XINERAMA=yes])
|
AC_ARG_ENABLE(xinerama, AS_HELP_STRING([--disable-xinerama], [Build Xinerama extension (default: enabled)]), [XINERAMA=$enableval], [XINERAMA=yes])
|
||||||
AC_ARG_ENABLE(xf86vidmode, AS_HELP_STRING([--disable-xf86vidmode], [Build XF86VidMode extension (default: auto)]), [XF86VIDMODE=$enableval], [XF86VIDMODE=auto])
|
AC_ARG_ENABLE(xf86vidmode, AS_HELP_STRING([--disable-xf86vidmode], [Build XF86VidMode extension (default: auto)]), [XF86VIDMODE=$enableval], [XF86VIDMODE=auto])
|
||||||
AC_ARG_ENABLE(xace, AS_HELP_STRING([--disable-xace], [Build X-ACE extension (default: enabled)]), [XACE=$enableval], [XACE=yes])
|
AC_ARG_ENABLE(xace, AS_HELP_STRING([--disable-xace], [Build X-ACE extension (default: enabled)]), [XACE=$enableval], [XACE=yes])
|
||||||
|
@ -807,6 +808,7 @@ DAMAGEPROTO="damageproto >= 1.1"
|
||||||
XCMISCPROTO="xcmiscproto >= 1.2.0"
|
XCMISCPROTO="xcmiscproto >= 1.2.0"
|
||||||
BIGREQSPROTO="bigreqsproto >= 1.1.0"
|
BIGREQSPROTO="bigreqsproto >= 1.1.0"
|
||||||
XTRANS="xtrans >= 1.2.2"
|
XTRANS="xtrans >= 1.2.2"
|
||||||
|
PRESENTPROTO="presentproto >= 1.0"
|
||||||
|
|
||||||
dnl List of libraries that require a specific version
|
dnl List of libraries that require a specific version
|
||||||
LIBAPPLEWM="applewm >= 1.4"
|
LIBAPPLEWM="applewm >= 1.4"
|
||||||
|
@ -1160,6 +1162,14 @@ if test "x$DRI2" = xyes; then
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL(DRI2_AIGLX, test "x$DRI2_AIGLX" = xyes)
|
AM_CONDITIONAL(DRI2_AIGLX, test "x$DRI2_AIGLX" = xyes)
|
||||||
|
|
||||||
|
AM_CONDITIONAL(PRESENT, [test "x$PRESENT" = xyes])
|
||||||
|
if test "x$PRESENT" = xyes; then
|
||||||
|
AC_DEFINE(PRESENT, 1, [Support Present extension])
|
||||||
|
REQUIRED_MODULES="$REQUIRED_MODULES $PRESENTPROTO"
|
||||||
|
SDK_REQUIRED_MODULES="$SDK_REQUIRED_MODULES $PRESENTPROTO"
|
||||||
|
PRESENT_INC='-I$(top_srcdir)/present'
|
||||||
|
PRESENT_LIB='$(top_builddir)/present/libpresent.la'
|
||||||
|
fi
|
||||||
|
|
||||||
AM_CONDITIONAL(XINERAMA, [test "x$XINERAMA" = xyes])
|
AM_CONDITIONAL(XINERAMA, [test "x$XINERAMA" = xyes])
|
||||||
if test "x$XINERAMA" = xyes; then
|
if test "x$XINERAMA" = xyes; then
|
||||||
|
@ -1584,7 +1594,7 @@ AC_EGREP_CPP([I_AM_SVR4],[
|
||||||
AC_DEFINE([SVR4],1,[Define to 1 on systems derived from System V Release 4])
|
AC_DEFINE([SVR4],1,[Define to 1 on systems derived from System V Release 4])
|
||||||
AC_MSG_RESULT([yes])], AC_MSG_RESULT([no]))
|
AC_MSG_RESULT([yes])], AC_MSG_RESULT([no]))
|
||||||
|
|
||||||
XSERVER_CFLAGS="$XSERVER_CFLAGS $CORE_INCS $XEXT_INC $COMPOSITE_INC $DAMAGE_INC $FIXES_INC $XI_INC $MI_INC $MIEXT_SYNC_INC $MIEXT_SHADOW_INC $MIEXT_LAYER_INC $MIEXT_DAMAGE_INC $RENDER_INC $RANDR_INC $FB_INC $DBE_INC"
|
XSERVER_CFLAGS="$XSERVER_CFLAGS $CORE_INCS $XEXT_INC $COMPOSITE_INC $DAMAGE_INC $FIXES_INC $XI_INC $MI_INC $MIEXT_SYNC_INC $MIEXT_SHADOW_INC $MIEXT_LAYER_INC $MIEXT_DAMAGE_INC $RENDER_INC $RANDR_INC $FB_INC $DBE_INC $PRESENT_INC"
|
||||||
|
|
||||||
dnl ---------------------------------------------------------------------------
|
dnl ---------------------------------------------------------------------------
|
||||||
dnl DDX section.
|
dnl DDX section.
|
||||||
|
@ -1597,7 +1607,7 @@ AC_MSG_RESULT([$XVFB])
|
||||||
AM_CONDITIONAL(XVFB, [test "x$XVFB" = xyes])
|
AM_CONDITIONAL(XVFB, [test "x$XVFB" = xyes])
|
||||||
|
|
||||||
if test "x$XVFB" = xyes; then
|
if test "x$XVFB" = xyes; then
|
||||||
XVFB_LIBS="$FB_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB"
|
XVFB_LIBS="$FB_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB"
|
||||||
XVFB_SYS_LIBS="$XVFBMODULES_LIBS $GLX_SYS_LIBS"
|
XVFB_SYS_LIBS="$XVFBMODULES_LIBS $GLX_SYS_LIBS"
|
||||||
AC_SUBST([XVFB_LIBS])
|
AC_SUBST([XVFB_LIBS])
|
||||||
AC_SUBST([XVFB_SYS_LIBS])
|
AC_SUBST([XVFB_SYS_LIBS])
|
||||||
|
@ -1618,7 +1628,7 @@ if test "x$XNEST" = xyes; then
|
||||||
if test "x$have_xnest" = xno; then
|
if test "x$have_xnest" = xno; then
|
||||||
AC_MSG_ERROR([Xnest build explicitly requested, but required modules not found.])
|
AC_MSG_ERROR([Xnest build explicitly requested, but required modules not found.])
|
||||||
fi
|
fi
|
||||||
XNEST_LIBS="$FB_LIB $FIXES_LIB $MI_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $MAIN_LIB $DIX_LIB $OS_LIB"
|
XNEST_LIBS="$FB_LIB $FIXES_LIB $MI_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $MAIN_LIB $DIX_LIB $OS_LIB"
|
||||||
XNEST_SYS_LIBS="$XNESTMODULES_LIBS $GLX_SYS_LIBS"
|
XNEST_SYS_LIBS="$XNESTMODULES_LIBS $GLX_SYS_LIBS"
|
||||||
AC_SUBST([XNEST_LIBS])
|
AC_SUBST([XNEST_LIBS])
|
||||||
AC_SUBST([XNEST_SYS_LIBS])
|
AC_SUBST([XNEST_SYS_LIBS])
|
||||||
|
@ -1643,7 +1653,7 @@ if test "x$XORG" = xyes; then
|
||||||
XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os'
|
XORG_OSINCS='-I$(top_srcdir)/hw/xfree86/os-support -I$(top_srcdir)/hw/xfree86/os-support/bus -I$(top_srcdir)/os'
|
||||||
XORG_INCS="$XORG_DDXINCS $XORG_OSINCS"
|
XORG_INCS="$XORG_DDXINCS $XORG_OSINCS"
|
||||||
XORG_CFLAGS="$XORGSERVER_CFLAGS -DHAVE_XORG_CONFIG_H"
|
XORG_CFLAGS="$XORGSERVER_CFLAGS -DHAVE_XORG_CONFIG_H"
|
||||||
XORG_LIBS="$COMPOSITE_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $XI_LIB $XKB_LIB"
|
XORG_LIBS="$COMPOSITE_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $XI_LIB $XKB_LIB"
|
||||||
|
|
||||||
dnl ==================================================================
|
dnl ==================================================================
|
||||||
dnl symbol visibility
|
dnl symbol visibility
|
||||||
|
@ -2056,7 +2066,7 @@ if test "x$DMX" = xyes; then
|
||||||
fi
|
fi
|
||||||
DMX_INCLUDES="$XEXT_INC $RENDER_INC $RECORD_INC"
|
DMX_INCLUDES="$XEXT_INC $RENDER_INC $RECORD_INC"
|
||||||
XDMX_CFLAGS="$DMXMODULES_CFLAGS"
|
XDMX_CFLAGS="$DMXMODULES_CFLAGS"
|
||||||
XDMX_LIBS="$FB_LIB $MI_LIB $XEXT_LIB $RENDER_LIB $RECORD_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $DRI3_LIB $MIEXT_SYNC_LIB $MIEXT_SHADOW_LIB $MIEXT_DAMAGE_LIB $COMPOSITE_LIB $DAMAGE_LIB $MAIN_LIB $DIX_LIB $CONFIG_LIB $OS_LIB $FIXES_LIB"
|
XDMX_LIBS="$FB_LIB $MI_LIB $XEXT_LIB $RENDER_LIB $RECORD_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_SHADOW_LIB $MIEXT_DAMAGE_LIB $COMPOSITE_LIB $DAMAGE_LIB $MAIN_LIB $DIX_LIB $CONFIG_LIB $OS_LIB $FIXES_LIB"
|
||||||
XDMX_SYS_LIBS="$DMXMODULES_LIBS"
|
XDMX_SYS_LIBS="$DMXMODULES_LIBS"
|
||||||
AC_SUBST([XDMX_CFLAGS])
|
AC_SUBST([XDMX_CFLAGS])
|
||||||
AC_SUBST([XDMX_LIBS])
|
AC_SUBST([XDMX_LIBS])
|
||||||
|
@ -2165,7 +2175,7 @@ if test "$KDRIVE" = yes; then
|
||||||
|
|
||||||
KDRIVE_CFLAGS="$XSERVER_CFLAGS -DHAVE_KDRIVE_CONFIG_H $TSLIB_CFLAGS"
|
KDRIVE_CFLAGS="$XSERVER_CFLAGS -DHAVE_KDRIVE_CONFIG_H $TSLIB_CFLAGS"
|
||||||
|
|
||||||
KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB"
|
KDRIVE_PURE_LIBS="$FB_LIB $MI_LIB $FIXES_LIB $XEXT_LIB $DBE_LIB $RECORD_LIB $GLX_LIBS $RANDR_LIB $RENDER_LIB $DAMAGE_LIB $DRI3_LIB $PRESENT_LIB $MIEXT_SYNC_LIB $MIEXT_DAMAGE_LIB $MIEXT_SHADOW_LIB $XI_LIB $XKB_LIB $XKB_STUB_LIB $COMPOSITE_LIB $OS_LIB"
|
||||||
KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la'
|
KDRIVE_LIB='$(top_builddir)/hw/kdrive/src/libkdrive.la'
|
||||||
case $host_os in
|
case $host_os in
|
||||||
*linux*)
|
*linux*)
|
||||||
|
@ -2288,6 +2298,7 @@ Xi/Makefile
|
||||||
xfixes/Makefile
|
xfixes/Makefile
|
||||||
exa/Makefile
|
exa/Makefile
|
||||||
dri3/Makefile
|
dri3/Makefile
|
||||||
|
present/Makefile
|
||||||
hw/Makefile
|
hw/Makefile
|
||||||
hw/xfree86/Makefile
|
hw/xfree86/Makefile
|
||||||
hw/xfree86/common/Makefile
|
hw/xfree86/common/Makefile
|
||||||
|
|
|
@ -68,6 +68,9 @@
|
||||||
* _any_ header files. */
|
* _any_ header files. */
|
||||||
extern FontPtr defaultFont;
|
extern FontPtr defaultFont;
|
||||||
|
|
||||||
|
/* Hack to get Present to build (present requires RandR) */
|
||||||
|
RESTYPE RRCrtcType;
|
||||||
|
|
||||||
/** This routine provides information to the DMX protocol extension
|
/** This routine provides information to the DMX protocol extension
|
||||||
* about a particular screen. */
|
* about a particular screen. */
|
||||||
Bool
|
Bool
|
||||||
|
|
|
@ -255,6 +255,9 @@
|
||||||
/* Internal define for Xinerama */
|
/* Internal define for Xinerama */
|
||||||
#undef PANORAMIX
|
#undef PANORAMIX
|
||||||
|
|
||||||
|
/* Support Present extension */
|
||||||
|
#undef PRESENT
|
||||||
|
|
||||||
/* Overall prefix */
|
/* Overall prefix */
|
||||||
#undef PROJECTROOT
|
#undef PROJECTROOT
|
||||||
|
|
||||||
|
|
|
@ -181,4 +181,9 @@ extern void XvMCExtensionInit(void);
|
||||||
extern void dri3_extension_init(void);
|
extern void dri3_extension_init(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(PRESENT)
|
||||||
|
#include <X11/extensions/presentproto.h>
|
||||||
|
#include "presentext.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -70,6 +70,9 @@
|
||||||
/* Internal define for Xinerama */
|
/* Internal define for Xinerama */
|
||||||
#undef PANORAMIX
|
#undef PANORAMIX
|
||||||
|
|
||||||
|
/* Support Present extension */
|
||||||
|
#undef PRESENT
|
||||||
|
|
||||||
/* Support RANDR extension */
|
/* Support RANDR extension */
|
||||||
#undef RANDR
|
#undef RANDR
|
||||||
|
|
||||||
|
|
|
@ -287,7 +287,10 @@ static ExtensionModule staticExtensions[] = {
|
||||||
#ifdef DPMSExtension
|
#ifdef DPMSExtension
|
||||||
{DPMSExtensionInit, DPMSExtensionName, &noDPMSExtension},
|
{DPMSExtensionInit, DPMSExtensionName, &noDPMSExtension},
|
||||||
#endif
|
#endif
|
||||||
|
{present_extension_init, PRESENT_NAME, NULL},
|
||||||
|
#ifdef DRI3
|
||||||
{dri3_extension_init, DRI3_NAME, NULL},
|
{dri3_extension_init, DRI3_NAME, NULL},
|
||||||
|
#endif
|
||||||
#ifdef RES
|
#ifdef RES
|
||||||
{ResExtensionInit, XRES_NAME, &noResExtension},
|
{ResExtensionInit, XRES_NAME, &noResExtension},
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
noinst_LTLIBRARIES = libpresent.la
|
||||||
|
AM_CFLAGS = \
|
||||||
|
-DHAVE_XORG_CONFIG_H \
|
||||||
|
@DIX_CFLAGS@ @XORG_CFLAGS@
|
||||||
|
|
||||||
|
libpresent_la_SOURCES = \
|
||||||
|
present.h \
|
||||||
|
present.c \
|
||||||
|
present_event.c \
|
||||||
|
present_fake.c \
|
||||||
|
present_fence.c \
|
||||||
|
present_notify.c \
|
||||||
|
present_priv.h \
|
||||||
|
present_request.c \
|
||||||
|
present_screen.c
|
||||||
|
|
||||||
|
sdk_HEADERS = present.h presentext.h
|
|
@ -0,0 +1,775 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2013 Keith Packard
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_XORG_CONFIG_H
|
||||||
|
#include <xorg-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "present_priv.h"
|
||||||
|
#include <gcstruct.h>
|
||||||
|
#include <misync.h>
|
||||||
|
#include <misyncstr.h>
|
||||||
|
#ifdef MONOTONIC_CLOCK
|
||||||
|
#include <time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static uint64_t present_event_id;
|
||||||
|
static struct xorg_list present_exec_queue;
|
||||||
|
static struct xorg_list present_flip_queue;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define DebugPresent(x) ErrorF x
|
||||||
|
#else
|
||||||
|
#define DebugPresent(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copies the update region from a pixmap to the target drawable
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
present_copy_region(DrawablePtr drawable,
|
||||||
|
PixmapPtr pixmap,
|
||||||
|
RegionPtr update,
|
||||||
|
int16_t x_off,
|
||||||
|
int16_t y_off)
|
||||||
|
{
|
||||||
|
ScreenPtr screen = drawable->pScreen;
|
||||||
|
GCPtr gc;
|
||||||
|
|
||||||
|
gc = GetScratchGC(drawable->depth, screen);
|
||||||
|
if (update) {
|
||||||
|
ChangeGCVal changes[2];
|
||||||
|
|
||||||
|
changes[0].val = x_off;
|
||||||
|
changes[1].val = y_off;
|
||||||
|
ChangeGC(serverClient, gc,
|
||||||
|
GCClipXOrigin|GCClipYOrigin,
|
||||||
|
changes);
|
||||||
|
(*gc->funcs->ChangeClip)(gc, CT_REGION, update, 0);
|
||||||
|
}
|
||||||
|
ValidateGC(drawable, gc);
|
||||||
|
(*gc->ops->CopyArea)(&pixmap->drawable,
|
||||||
|
drawable,
|
||||||
|
gc,
|
||||||
|
0, 0,
|
||||||
|
pixmap->drawable.width, pixmap->drawable.height,
|
||||||
|
x_off, y_off);
|
||||||
|
if (update)
|
||||||
|
(*gc->funcs->ChangeClip)(gc, CT_NONE, NULL, 0);
|
||||||
|
FreeScratchGC(gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
present_check_flip(RRCrtcPtr crtc,
|
||||||
|
WindowPtr window,
|
||||||
|
PixmapPtr pixmap,
|
||||||
|
Bool sync_flip,
|
||||||
|
RegionPtr valid,
|
||||||
|
int16_t x_off,
|
||||||
|
int16_t y_off)
|
||||||
|
{
|
||||||
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
|
WindowPtr root = screen->root;
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
if (!screen_priv)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!screen_priv->info)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!crtc)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Check to see if the driver supports flips at all */
|
||||||
|
if (!screen_priv->info->flip)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Can't pend a flip while unflipping */
|
||||||
|
if (screen_priv->unflip_event_id) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can't have two pending flips at the same time */
|
||||||
|
if (screen_priv->flip_pending) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure the window hasn't been redirected with Composite */
|
||||||
|
if (screen->GetWindowPixmap(window) != screen->GetScreenPixmap(screen))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Check for full-screen window */
|
||||||
|
if (!RegionEqual(&window->clipList, &root->winSize)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Source pixmap must align with window exactly */
|
||||||
|
if (x_off || y_off) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure the area marked as valid fills the screen */
|
||||||
|
if (valid && !RegionEqual(valid, &root->winSize)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Does the window match the pixmap exactly? */
|
||||||
|
if (window->drawable.x != 0 || window->drawable.y != 0 ||
|
||||||
|
#ifdef COMPOSITE
|
||||||
|
window->drawable.x != pixmap->screen_x || window->drawable.y != pixmap->screen_y ||
|
||||||
|
#endif
|
||||||
|
window->drawable.width != pixmap->drawable.width ||
|
||||||
|
window->drawable.height != pixmap->drawable.height) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ask the driver for permission */
|
||||||
|
if (screen_priv->info->check_flip) {
|
||||||
|
if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
present_flip(RRCrtcPtr crtc,
|
||||||
|
uint64_t event_id,
|
||||||
|
uint64_t target_msc,
|
||||||
|
PixmapPtr pixmap,
|
||||||
|
Bool sync_flip)
|
||||||
|
{
|
||||||
|
ScreenPtr screen = crtc->pScreen;
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
return (*screen_priv->info->flip) (crtc, event_id, target_msc, pixmap, sync_flip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_vblank_notify(present_vblank_ptr vblank, CARD8 kind, CARD8 mode, uint64_t ust, uint64_t crtc_msc)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
present_send_complete_notify(vblank->window, kind, mode, vblank->serial, ust, crtc_msc - vblank->msc_offset);
|
||||||
|
for (n = 0; n < vblank->num_notifies; n++) {
|
||||||
|
WindowPtr window = vblank->notifies[n].window;
|
||||||
|
CARD32 serial = vblank->notifies[n].serial;
|
||||||
|
|
||||||
|
if (window)
|
||||||
|
present_send_complete_notify(window, kind, mode, serial, ust, crtc_msc - vblank->msc_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_pixmap_idle(PixmapPtr pixmap, WindowPtr window, CARD32 serial, struct present_fence *present_fence)
|
||||||
|
{
|
||||||
|
present_fence_set_triggered(present_fence);
|
||||||
|
present_send_idle_notify(window, serial, pixmap, present_fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
RRCrtcPtr
|
||||||
|
present_get_crtc(WindowPtr window)
|
||||||
|
{
|
||||||
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
if (!screen_priv)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!screen_priv->info)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return (*screen_priv->info->get_crtc)(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
present_query_capabilities(RRCrtcPtr crtc)
|
||||||
|
{
|
||||||
|
present_screen_priv_ptr screen_priv;
|
||||||
|
|
||||||
|
if (!crtc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
screen_priv = present_screen_priv(crtc->pScreen);
|
||||||
|
|
||||||
|
if (!screen_priv)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!screen_priv->info)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return screen_priv->info->capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
present_get_ust_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t *ust, uint64_t *msc)
|
||||||
|
{
|
||||||
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
if (crtc == NULL)
|
||||||
|
return present_fake_get_ust_msc(screen, ust, msc);
|
||||||
|
else
|
||||||
|
return (*screen_priv->info->get_ust_msc)(crtc, ust, msc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_flush(WindowPtr window)
|
||||||
|
{
|
||||||
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
if (!screen_priv)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!screen_priv->info)
|
||||||
|
return;
|
||||||
|
|
||||||
|
(*screen_priv->info->flush) (window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
present_queue_vblank(ScreenPtr screen,
|
||||||
|
RRCrtcPtr crtc,
|
||||||
|
uint64_t event_id,
|
||||||
|
uint64_t msc)
|
||||||
|
{
|
||||||
|
Bool ret;
|
||||||
|
|
||||||
|
if (crtc == NULL)
|
||||||
|
ret = present_fake_queue_vblank(screen, event_id, msc);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
ret = (*screen_priv->info->queue_vblank) (crtc, event_id, msc);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t
|
||||||
|
present_window_to_crtc_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t window_msc, uint64_t new_msc)
|
||||||
|
{
|
||||||
|
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
|
||||||
|
|
||||||
|
if (crtc != window_priv->crtc) {
|
||||||
|
uint64_t old_ust, old_msc;
|
||||||
|
|
||||||
|
/* The old CRTC may have been turned off, in which case
|
||||||
|
* we'll just use whatever previous MSC we'd seen from this CRTC
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (present_get_ust_msc(window, window_priv->crtc, &old_ust, &old_msc) != Success)
|
||||||
|
old_msc = window_priv->msc;
|
||||||
|
|
||||||
|
window_priv->msc_offset += new_msc - old_msc;
|
||||||
|
window_priv->crtc = crtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return window_msc + window_priv->msc_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_flip_idle(ScreenPtr screen)
|
||||||
|
{
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
if (screen_priv->flip_pixmap) {
|
||||||
|
present_pixmap_idle(screen_priv->flip_pixmap, screen_priv->flip_window,
|
||||||
|
screen_priv->flip_serial, screen_priv->flip_idle_fence);
|
||||||
|
present_fence_destroy(screen_priv->flip_idle_fence);
|
||||||
|
dixDestroyPixmap(screen_priv->flip_pixmap, screen_priv->flip_pixmap->drawable.id);
|
||||||
|
screen_priv->flip_crtc = NULL;
|
||||||
|
screen_priv->flip_window = NULL;
|
||||||
|
screen_priv->flip_serial = 0;
|
||||||
|
screen_priv->flip_pixmap = NULL;
|
||||||
|
screen_priv->flip_idle_fence = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_unflip(ScreenPtr screen)
|
||||||
|
{
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
assert (!screen_priv->unflip_event_id);
|
||||||
|
assert (!screen_priv->flip_pending);
|
||||||
|
|
||||||
|
/* Update the screen pixmap with the current flip pixmap contents
|
||||||
|
*/
|
||||||
|
if (screen_priv->flip_pixmap) {
|
||||||
|
present_copy_region(&screen->GetScreenPixmap(screen)->drawable,
|
||||||
|
screen_priv->flip_pixmap,
|
||||||
|
NULL, 0, 0);
|
||||||
|
}
|
||||||
|
screen_priv->unflip_event_id = ++present_event_id;
|
||||||
|
DebugPresent(("u %lld\n", screen_priv->unflip_event_id));
|
||||||
|
(*screen_priv->info->unflip) (screen, screen_priv->unflip_event_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc);
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
|
||||||
|
{
|
||||||
|
WindowPtr window = vblank->window;
|
||||||
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
DebugPresent(("\tn %p %8lld: %08lx -> %08lx\n", vblank, vblank->target_msc,
|
||||||
|
vblank->pixmap ? vblank->pixmap->drawable.id : 0,
|
||||||
|
vblank->window->drawable.id));
|
||||||
|
|
||||||
|
assert (vblank == screen_priv->flip_pending);
|
||||||
|
|
||||||
|
present_flip_idle(screen);
|
||||||
|
|
||||||
|
/* Transfer reference for pixmap and fence from vblank to screen_priv */
|
||||||
|
screen_priv->flip_crtc = vblank->crtc;
|
||||||
|
screen_priv->flip_window = vblank->window;
|
||||||
|
screen_priv->flip_serial = vblank->serial;
|
||||||
|
screen_priv->flip_pixmap = vblank->pixmap;
|
||||||
|
screen_priv->flip_idle_fence = vblank->idle_fence;
|
||||||
|
|
||||||
|
vblank->pixmap = NULL;
|
||||||
|
vblank->idle_fence = NULL;
|
||||||
|
|
||||||
|
screen_priv->flip_pending = NULL;
|
||||||
|
|
||||||
|
if (vblank->abort_flip)
|
||||||
|
present_unflip(screen);
|
||||||
|
|
||||||
|
if (!vblank->window_destroyed)
|
||||||
|
present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc);
|
||||||
|
present_vblank_destroy(vblank);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc)
|
||||||
|
{
|
||||||
|
present_vblank_ptr vblank, tmp;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
xorg_list_for_each_entry_safe(vblank, tmp, &present_exec_queue, event_queue) {
|
||||||
|
if (vblank->event_id == event_id) {
|
||||||
|
xorg_list_del(&vblank->event_queue);
|
||||||
|
present_execute(vblank, ust, msc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xorg_list_for_each_entry_safe(vblank, tmp, &present_flip_queue, event_queue) {
|
||||||
|
if (vblank->event_id == event_id) {
|
||||||
|
xorg_list_del(&vblank->event_queue);
|
||||||
|
present_flip_notify(vblank, ust, msc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s = 0; s < screenInfo.numScreens; s++) {
|
||||||
|
ScreenPtr screen = screenInfo.screens[s];
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
if (event_id == screen_priv->unflip_event_id) {
|
||||||
|
DebugPresent(("\tun %lld\n", event_id));
|
||||||
|
screen_priv->unflip_event_id = 0;
|
||||||
|
present_flip_idle(screen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'window' is being reconfigured. Check to see if it is involved
|
||||||
|
* in flipping and clean up as necessary
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
present_check_flip_window (WindowPtr window)
|
||||||
|
{
|
||||||
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
present_window_priv_ptr window_priv = present_window_priv(window);
|
||||||
|
present_vblank_ptr flip_pending = screen_priv->flip_pending;
|
||||||
|
present_vblank_ptr vblank;
|
||||||
|
|
||||||
|
/* If this window hasn't ever been used with Present, it can't be
|
||||||
|
* flipping
|
||||||
|
*/
|
||||||
|
if (!window_priv)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (screen_priv->unflip_event_id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (flip_pending) {
|
||||||
|
/*
|
||||||
|
* Check pending flip
|
||||||
|
*/
|
||||||
|
if (flip_pending->window == window) {
|
||||||
|
if (!present_check_flip(flip_pending->crtc, window, flip_pending->pixmap,
|
||||||
|
flip_pending->sync_flip, NULL, 0, 0))
|
||||||
|
flip_pending->abort_flip = TRUE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Check current flip
|
||||||
|
*/
|
||||||
|
if (window == screen_priv->flip_window) {
|
||||||
|
if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, FALSE, NULL, 0, 0))
|
||||||
|
present_unflip(screen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now check any queued vblanks */
|
||||||
|
xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
|
||||||
|
if (vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, FALSE, NULL, 0, 0))
|
||||||
|
vblank->flip = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Once the required MSC has been reached, execute the pending request.
|
||||||
|
*
|
||||||
|
* For requests to actually present something, either blt contents to
|
||||||
|
* the screen or queue a frame buffer swap.
|
||||||
|
*
|
||||||
|
* For requests to just get the current MSC/UST combo, skip that part and
|
||||||
|
* go straight to event delivery
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
|
||||||
|
{
|
||||||
|
WindowPtr window = vblank->window;
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(window->drawable.pScreen);
|
||||||
|
|
||||||
|
if (vblank->wait_fence) {
|
||||||
|
/* XXX check fence, queue if not ready */
|
||||||
|
}
|
||||||
|
|
||||||
|
xorg_list_del(&vblank->event_queue);
|
||||||
|
if (vblank->pixmap) {
|
||||||
|
|
||||||
|
if (vblank->flip && screen_priv->flip_pending == NULL && !screen_priv->unflip_event_id) {
|
||||||
|
|
||||||
|
DebugPresent(("\tf %p %8lld: %08lx -> %08lx\n", vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id));
|
||||||
|
/* Prepare to flip by removing from the window/screen lists
|
||||||
|
* and sticking it into the flip_pending field
|
||||||
|
*/
|
||||||
|
screen_priv->flip_pending = vblank;
|
||||||
|
xorg_list_del(&vblank->window_list);
|
||||||
|
|
||||||
|
xorg_list_add(&vblank->event_queue, &present_flip_queue);
|
||||||
|
/* Try to flip
|
||||||
|
*/
|
||||||
|
if (present_flip(vblank->crtc, vblank->event_id, vblank->target_msc, vblank->pixmap, vblank->sync_flip))
|
||||||
|
return;
|
||||||
|
|
||||||
|
xorg_list_del(&vblank->event_queue);
|
||||||
|
/* Oops, flip failed. Clear the flip_pending field
|
||||||
|
*/
|
||||||
|
screen_priv->flip_pending = NULL;
|
||||||
|
vblank->flip = FALSE;
|
||||||
|
}
|
||||||
|
DebugPresent(("\tc %p %8lld: %08lx -> %08lx\n", vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id));
|
||||||
|
if (screen_priv->flip_pending) {
|
||||||
|
|
||||||
|
/* Check pending flip
|
||||||
|
*/
|
||||||
|
if (window == screen_priv->flip_pending->window)
|
||||||
|
screen_priv->flip_pending->abort_flip = TRUE;
|
||||||
|
} else if (!screen_priv->unflip_event_id) {
|
||||||
|
|
||||||
|
/* Check current flip
|
||||||
|
*/
|
||||||
|
if (window == screen_priv->flip_window)
|
||||||
|
present_unflip(window->drawable.pScreen);
|
||||||
|
}
|
||||||
|
present_copy_region(&window->drawable, vblank->pixmap, vblank->update, vblank->x_off, vblank->y_off);
|
||||||
|
|
||||||
|
/* present_copy_region sticks the region into a scratch GC,
|
||||||
|
* which is then freed, freeing the region
|
||||||
|
*/
|
||||||
|
vblank->update = NULL;
|
||||||
|
present_flush(window);
|
||||||
|
|
||||||
|
present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
|
||||||
|
}
|
||||||
|
present_vblank_notify(vblank, vblank->kind, PresentCompleteModeCopy, ust, crtc_msc);
|
||||||
|
present_vblank_destroy(vblank);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
present_pixmap(WindowPtr window,
|
||||||
|
PixmapPtr pixmap,
|
||||||
|
CARD32 serial,
|
||||||
|
RegionPtr valid,
|
||||||
|
RegionPtr update,
|
||||||
|
int16_t x_off,
|
||||||
|
int16_t y_off,
|
||||||
|
RRCrtcPtr target_crtc,
|
||||||
|
SyncFence *wait_fence,
|
||||||
|
SyncFence *idle_fence,
|
||||||
|
uint32_t options,
|
||||||
|
uint64_t window_msc,
|
||||||
|
uint64_t divisor,
|
||||||
|
uint64_t remainder,
|
||||||
|
present_notify_ptr notifies,
|
||||||
|
int num_notifies)
|
||||||
|
{
|
||||||
|
uint64_t ust;
|
||||||
|
uint64_t target_msc;
|
||||||
|
uint64_t crtc_msc;
|
||||||
|
int ret;
|
||||||
|
present_vblank_ptr vblank;
|
||||||
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
|
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
if (!window_priv)
|
||||||
|
return BadAlloc;
|
||||||
|
|
||||||
|
if (!target_crtc) {
|
||||||
|
/* Update the CRTC if we have a pixmap or we don't have a CRTC
|
||||||
|
*/
|
||||||
|
if (!pixmap)
|
||||||
|
target_crtc = window_priv->crtc;
|
||||||
|
|
||||||
|
if (!target_crtc)
|
||||||
|
target_crtc = present_get_crtc(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
present_get_ust_msc(window, target_crtc, &ust, &crtc_msc);
|
||||||
|
|
||||||
|
target_msc = present_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc);
|
||||||
|
|
||||||
|
/* Stash the current MSC away in case we need it later
|
||||||
|
*/
|
||||||
|
window_priv->msc = crtc_msc;
|
||||||
|
|
||||||
|
/* Adjust target_msc to match modulus
|
||||||
|
*/
|
||||||
|
if (crtc_msc >= target_msc) {
|
||||||
|
if (divisor != 0) {
|
||||||
|
target_msc = crtc_msc - (crtc_msc % divisor) + remainder;
|
||||||
|
if (target_msc <= crtc_msc)
|
||||||
|
target_msc += divisor;
|
||||||
|
} else
|
||||||
|
target_msc = crtc_msc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for a matching presentation already on the list and
|
||||||
|
* don't bother doing the previous one if this one will overwrite it
|
||||||
|
* in the same frame
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!update) {
|
||||||
|
xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
|
||||||
|
|
||||||
|
if (!vblank->pixmap)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (vblank->crtc != target_crtc || vblank->target_msc != target_msc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
|
||||||
|
present_fence_destroy(vblank->idle_fence);
|
||||||
|
dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
|
||||||
|
|
||||||
|
vblank->pixmap = NULL;
|
||||||
|
vblank->idle_fence = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vblank = calloc (1, sizeof (present_vblank_rec));
|
||||||
|
if (!vblank)
|
||||||
|
return BadAlloc;
|
||||||
|
|
||||||
|
xorg_list_append(&vblank->window_list, &window_priv->vblank);
|
||||||
|
xorg_list_init(&vblank->event_queue);
|
||||||
|
|
||||||
|
vblank->screen = screen;
|
||||||
|
vblank->window = window;
|
||||||
|
vblank->pixmap = pixmap;
|
||||||
|
vblank->event_id = ++present_event_id;
|
||||||
|
if (pixmap) {
|
||||||
|
vblank->kind = PresentCompleteKindPixmap;
|
||||||
|
pixmap->refcnt++;
|
||||||
|
} else
|
||||||
|
vblank->kind = PresentCompleteKindNotifyMSC;
|
||||||
|
|
||||||
|
vblank->serial = serial;
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
vblank->valid = RegionDuplicate(valid);
|
||||||
|
if (!vblank->valid)
|
||||||
|
goto no_mem;
|
||||||
|
}
|
||||||
|
if (update) {
|
||||||
|
vblank->update = RegionDuplicate(update);
|
||||||
|
if (!vblank->update)
|
||||||
|
goto no_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
vblank->x_off = x_off;
|
||||||
|
vblank->y_off = y_off;
|
||||||
|
vblank->target_msc = target_msc;
|
||||||
|
vblank->crtc = target_crtc;
|
||||||
|
vblank->msc_offset = window_priv->msc_offset;
|
||||||
|
vblank->notifies = notifies;
|
||||||
|
vblank->num_notifies = num_notifies;
|
||||||
|
|
||||||
|
if (!screen_priv->info || !(screen_priv->info->capabilities & PresentCapabilityAsync))
|
||||||
|
vblank->sync_flip = TRUE;
|
||||||
|
|
||||||
|
if (pixmap && present_check_flip (target_crtc, window, pixmap, vblank->sync_flip, valid, x_off, y_off)) {
|
||||||
|
vblank->flip = TRUE;
|
||||||
|
if (vblank->sync_flip)
|
||||||
|
target_msc--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idle_fence) {
|
||||||
|
vblank->idle_fence = present_fence_create(idle_fence);
|
||||||
|
if (!vblank->idle_fence)
|
||||||
|
goto no_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixmap)
|
||||||
|
DebugPresent(("q %p %8lld: %08lx -> %08lx (crtc %d)\n",
|
||||||
|
vblank, target_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id, target_crtc ? 1 : 0));
|
||||||
|
|
||||||
|
xorg_list_add(&vblank->event_queue, &present_exec_queue);
|
||||||
|
if (target_msc >= crtc_msc) {
|
||||||
|
ret = present_queue_vblank(screen, target_crtc, vblank->event_id, target_msc);
|
||||||
|
if (ret != Success) {
|
||||||
|
xorg_list_del(&vblank->event_queue);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
present_execute(vblank, ust, crtc_msc);
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
|
||||||
|
no_mem:
|
||||||
|
ret = BadAlloc;
|
||||||
|
failure:
|
||||||
|
vblank->notifies = NULL;
|
||||||
|
present_vblank_destroy(vblank);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_abort_vblank(ScreenPtr screen, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
|
||||||
|
{
|
||||||
|
present_vblank_ptr vblank, tmp;
|
||||||
|
|
||||||
|
if (crtc == NULL)
|
||||||
|
present_fake_abort_vblank(screen, event_id, msc);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
(*screen_priv->info->abort_vblank) (crtc, event_id, msc);
|
||||||
|
}
|
||||||
|
|
||||||
|
xorg_list_for_each_entry_safe(vblank, tmp, &present_exec_queue, event_queue) {
|
||||||
|
if (vblank->event_id == event_id) {
|
||||||
|
xorg_list_del(&vblank->event_queue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xorg_list_for_each_entry_safe(vblank, tmp, &present_flip_queue, event_queue) {
|
||||||
|
if (vblank->event_id == event_id) {
|
||||||
|
xorg_list_del(&vblank->event_queue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
present_notify_msc(WindowPtr window,
|
||||||
|
CARD32 serial,
|
||||||
|
uint64_t target_msc,
|
||||||
|
uint64_t divisor,
|
||||||
|
uint64_t remainder)
|
||||||
|
{
|
||||||
|
return present_pixmap(window,
|
||||||
|
NULL,
|
||||||
|
serial,
|
||||||
|
NULL, NULL,
|
||||||
|
0, 0,
|
||||||
|
NULL,
|
||||||
|
NULL, NULL,
|
||||||
|
0,
|
||||||
|
target_msc, divisor, remainder, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_flip_destroy(ScreenPtr screen)
|
||||||
|
{
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
/* XXX this needs to be synchronous for server reset */
|
||||||
|
|
||||||
|
/* Do the actual cleanup once the flip has been performed by the hardware */
|
||||||
|
if (screen_priv->flip_pending)
|
||||||
|
screen_priv->flip_pending->abort_flip = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_vblank_destroy(present_vblank_ptr vblank)
|
||||||
|
{
|
||||||
|
/* Remove vblank from window and screen lists */
|
||||||
|
xorg_list_del(&vblank->window_list);
|
||||||
|
|
||||||
|
DebugPresent(("\td %p %8lld: %08lx -> %08lx\n", vblank, vblank->target_msc,
|
||||||
|
vblank->pixmap ? vblank->pixmap->drawable.id : 0,
|
||||||
|
vblank->window->drawable.id));
|
||||||
|
|
||||||
|
/* Drop pixmap reference */
|
||||||
|
if (vblank->pixmap)
|
||||||
|
dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
|
||||||
|
|
||||||
|
/* Free regions */
|
||||||
|
if (vblank->valid)
|
||||||
|
RegionDestroy(vblank->valid);
|
||||||
|
if (vblank->update)
|
||||||
|
RegionDestroy(vblank->update);
|
||||||
|
|
||||||
|
if (vblank->idle_fence)
|
||||||
|
present_fence_destroy(vblank->idle_fence);
|
||||||
|
|
||||||
|
if (vblank->notifies)
|
||||||
|
present_destroy_notifies(vblank->notifies, vblank->num_notifies);
|
||||||
|
|
||||||
|
free(vblank);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool
|
||||||
|
present_init(void)
|
||||||
|
{
|
||||||
|
xorg_list_init(&present_exec_queue);
|
||||||
|
xorg_list_init(&present_flip_queue);
|
||||||
|
present_fake_queue_init();
|
||||||
|
return TRUE;
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2013 Keith Packard
|
||||||
|
*
|
||||||
|
* 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 _PRESENT_H_
|
||||||
|
#define _PRESENT_H_
|
||||||
|
|
||||||
|
#include <X11/extensions/presentproto.h>
|
||||||
|
#include "randrstr.h"
|
||||||
|
#include "presentext.h"
|
||||||
|
|
||||||
|
typedef struct present_vblank present_vblank_rec, *present_vblank_ptr;
|
||||||
|
|
||||||
|
/* Return the current CRTC for 'window'.
|
||||||
|
*/
|
||||||
|
typedef RRCrtcPtr (*present_get_crtc_ptr) (WindowPtr window);
|
||||||
|
|
||||||
|
/* Return the current ust/msc for 'crtc'
|
||||||
|
*/
|
||||||
|
typedef int (*present_get_ust_msc_ptr) (RRCrtcPtr crtc, uint64_t *ust, uint64_t *msc);
|
||||||
|
|
||||||
|
/* Queue callback on 'crtc' for time 'msc'. Call present_event_notify with 'event_id'
|
||||||
|
* at or after 'msc'. Return false if it didn't happen (which might occur if 'crtc'
|
||||||
|
* is not currently generating vblanks).
|
||||||
|
*/
|
||||||
|
typedef Bool (*present_queue_vblank_ptr) (RRCrtcPtr crtc,
|
||||||
|
uint64_t event_id,
|
||||||
|
uint64_t msc);
|
||||||
|
|
||||||
|
/* Abort pending vblank. The extension is no longer interested in
|
||||||
|
* 'event_id' which was to be notified at 'msc'. If possible, the
|
||||||
|
* driver is free to de-queue the notification.
|
||||||
|
*/
|
||||||
|
typedef void (*present_abort_vblank_ptr) (RRCrtcPtr crtc, uint64_t event_id, uint64_t msc);
|
||||||
|
|
||||||
|
/* Flush pending drawing on 'window' to the hardware.
|
||||||
|
*/
|
||||||
|
typedef void (*present_flush_ptr) (WindowPtr window);
|
||||||
|
|
||||||
|
/* Check if 'pixmap' is suitable for flipping to 'window'.
|
||||||
|
*/
|
||||||
|
typedef Bool (*present_check_flip_ptr) (RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip);
|
||||||
|
|
||||||
|
/* Flip pixmap, return false if it didn't happen.
|
||||||
|
*
|
||||||
|
* 'crtc' is to be used for any necessary synchronization.
|
||||||
|
*
|
||||||
|
* 'sync_flip' requests that the flip be performed at the next
|
||||||
|
* vertical blank interval to avoid tearing artifacts. If false, the
|
||||||
|
* flip should be performed as soon as possible.
|
||||||
|
*
|
||||||
|
* present_event_notify should be called with 'event_id' when the flip
|
||||||
|
* occurs
|
||||||
|
*/
|
||||||
|
typedef Bool (*present_flip_ptr) (RRCrtcPtr crtc,
|
||||||
|
uint64_t event_id,
|
||||||
|
uint64_t target_msc,
|
||||||
|
PixmapPtr pixmap,
|
||||||
|
Bool sync_flip);
|
||||||
|
|
||||||
|
/* "unflip" back to the regular screen scanout buffer
|
||||||
|
*
|
||||||
|
* present_event_notify should be called with 'event_id' when the unflip occurs.
|
||||||
|
*/
|
||||||
|
typedef void (*present_unflip_ptr) (ScreenPtr screen,
|
||||||
|
uint64_t event_id);
|
||||||
|
|
||||||
|
#define PRESENT_SCREEN_INFO_VERSION 0
|
||||||
|
|
||||||
|
typedef struct present_screen_info {
|
||||||
|
uint32_t version;
|
||||||
|
|
||||||
|
present_get_crtc_ptr get_crtc;
|
||||||
|
present_get_ust_msc_ptr get_ust_msc;
|
||||||
|
present_queue_vblank_ptr queue_vblank;
|
||||||
|
present_abort_vblank_ptr abort_vblank;
|
||||||
|
present_flush_ptr flush;
|
||||||
|
uint32_t capabilities;
|
||||||
|
present_check_flip_ptr check_flip;
|
||||||
|
present_flip_ptr flip;
|
||||||
|
present_unflip_ptr unflip;
|
||||||
|
|
||||||
|
} present_screen_info_rec, *present_screen_info_ptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when 'event_id' occurs. 'ust' and 'msc' indicate when the
|
||||||
|
* event actually happened
|
||||||
|
*/
|
||||||
|
extern _X_EXPORT void
|
||||||
|
present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc);
|
||||||
|
|
||||||
|
/* 'crtc' has been turned off, so any pending events will never occur.
|
||||||
|
*/
|
||||||
|
extern _X_EXPORT void
|
||||||
|
present_event_abandon(RRCrtcPtr crtc);
|
||||||
|
|
||||||
|
extern _X_EXPORT Bool
|
||||||
|
present_screen_init(ScreenPtr screen, present_screen_info_ptr info);
|
||||||
|
|
||||||
|
#endif /* _PRESENT_H_ */
|
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2013 Keith Packard
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_XORG_CONFIG_H
|
||||||
|
#include <xorg-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "present_priv.h"
|
||||||
|
|
||||||
|
#include "present_priv.h"
|
||||||
|
|
||||||
|
RESTYPE present_event_type;
|
||||||
|
|
||||||
|
static int
|
||||||
|
present_free_event(pointer data, XID id)
|
||||||
|
{
|
||||||
|
present_event_ptr present_event = (present_event_ptr) data;
|
||||||
|
present_window_priv_ptr window_priv = present_window_priv(present_event->window);
|
||||||
|
present_event_ptr *previous, current;
|
||||||
|
|
||||||
|
for (previous = &window_priv->events; (current = *previous); previous = ¤t->next) {
|
||||||
|
if (current == present_event) {
|
||||||
|
*previous = present_event->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free((pointer) present_event);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_free_events(WindowPtr window)
|
||||||
|
{
|
||||||
|
present_window_priv_ptr window_priv = present_window_priv(window);
|
||||||
|
present_event_ptr event;
|
||||||
|
|
||||||
|
if (!window_priv)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while ((event = window_priv->events))
|
||||||
|
FreeResource(event->id, RT_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_event_swap(xGenericEvent *from, xGenericEvent *to)
|
||||||
|
{
|
||||||
|
*to = *from;
|
||||||
|
swaps(&to->sequenceNumber);
|
||||||
|
swapl(&to->length);
|
||||||
|
swaps(&to->evtype);
|
||||||
|
switch (from->evtype) {
|
||||||
|
case PresentConfigureNotify: {
|
||||||
|
xPresentConfigureNotify *c = (xPresentConfigureNotify *) to;
|
||||||
|
|
||||||
|
swapl(&c->eid);
|
||||||
|
swapl(&c->window);
|
||||||
|
swaps(&c->x);
|
||||||
|
swaps(&c->y);
|
||||||
|
swaps(&c->width);
|
||||||
|
swaps(&c->height);
|
||||||
|
swaps(&c->off_x);
|
||||||
|
swaps(&c->off_y);
|
||||||
|
swaps(&c->pixmap_width);
|
||||||
|
swaps(&c->pixmap_height);
|
||||||
|
swapl(&c->pixmap_flags);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PresentCompleteNotify:
|
||||||
|
{
|
||||||
|
xPresentCompleteNotify *c = (xPresentCompleteNotify *) to;
|
||||||
|
swapl(&c->eid);
|
||||||
|
swapl(&c->window);
|
||||||
|
swapl(&c->serial);
|
||||||
|
swapll(&c->ust);
|
||||||
|
swapll(&c->msc);
|
||||||
|
}
|
||||||
|
case PresentIdleNotify:
|
||||||
|
{
|
||||||
|
xPresentIdleNotify *c = (xPresentIdleNotify *) to;
|
||||||
|
swapl(&c->eid);
|
||||||
|
swapl(&c->window);
|
||||||
|
swapl(&c->serial);
|
||||||
|
swapl(&c->idle_fence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_send_config_notify(WindowPtr window, int x, int y, int w, int h, int bw, WindowPtr sibling)
|
||||||
|
{
|
||||||
|
present_window_priv_ptr window_priv = present_window_priv(window);
|
||||||
|
|
||||||
|
if (window_priv) {
|
||||||
|
xPresentConfigureNotify cn = {
|
||||||
|
.type = GenericEvent,
|
||||||
|
.extension = present_request,
|
||||||
|
.length = (sizeof(xPresentConfigureNotify) - 32) >> 2,
|
||||||
|
.evtype = PresentConfigureNotify,
|
||||||
|
.eid = 0,
|
||||||
|
.window = window->drawable.id,
|
||||||
|
.x = x,
|
||||||
|
.y = y,
|
||||||
|
.width = w,
|
||||||
|
.height = h,
|
||||||
|
.off_x = 0,
|
||||||
|
.off_y = 0,
|
||||||
|
.pixmap_width = w,
|
||||||
|
.pixmap_height = h,
|
||||||
|
.pixmap_flags = 0
|
||||||
|
};
|
||||||
|
present_event_ptr event;
|
||||||
|
|
||||||
|
for (event = window_priv->events; event; event = event->next) {
|
||||||
|
if (event->mask & (1 << PresentConfigureNotify)) {
|
||||||
|
cn.eid = event->id;
|
||||||
|
WriteEventsToClient(event->client, 1, (xEvent *) &cn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_send_complete_notify(WindowPtr window, CARD8 kind, CARD8 mode, CARD32 serial, uint64_t ust, uint64_t msc)
|
||||||
|
{
|
||||||
|
present_window_priv_ptr window_priv = present_window_priv(window);
|
||||||
|
|
||||||
|
if (window_priv) {
|
||||||
|
xPresentCompleteNotify cn = {
|
||||||
|
.type = GenericEvent,
|
||||||
|
.extension = present_request,
|
||||||
|
.length = (sizeof(xPresentCompleteNotify) - 32) >> 2,
|
||||||
|
.evtype = PresentCompleteNotify,
|
||||||
|
.kind = kind,
|
||||||
|
.mode = mode,
|
||||||
|
.eid = 0,
|
||||||
|
.window = window->drawable.id,
|
||||||
|
.serial = serial,
|
||||||
|
.ust = ust,
|
||||||
|
.msc = msc,
|
||||||
|
};
|
||||||
|
present_event_ptr event;
|
||||||
|
|
||||||
|
for (event = window_priv->events; event; event = event->next) {
|
||||||
|
if (event->mask & PresentCompleteNotifyMask) {
|
||||||
|
cn.eid = event->id;
|
||||||
|
WriteEventsToClient(event->client, 1, (xEvent *) &cn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_send_idle_notify(WindowPtr window, CARD32 serial, PixmapPtr pixmap, struct present_fence *idle_fence)
|
||||||
|
{
|
||||||
|
present_window_priv_ptr window_priv = present_window_priv(window);
|
||||||
|
|
||||||
|
if (window_priv) {
|
||||||
|
xPresentIdleNotify in = {
|
||||||
|
.type = GenericEvent,
|
||||||
|
.extension = present_request,
|
||||||
|
.length = (sizeof(xPresentIdleNotify) - 32) >> 2,
|
||||||
|
.evtype = PresentIdleNotify,
|
||||||
|
.eid = 0,
|
||||||
|
.window = window->drawable.id,
|
||||||
|
.serial = serial,
|
||||||
|
.pixmap = pixmap->drawable.id,
|
||||||
|
.idle_fence = present_fence_id(idle_fence)
|
||||||
|
};
|
||||||
|
present_event_ptr event;
|
||||||
|
|
||||||
|
for (event = window_priv->events; event; event = event->next) {
|
||||||
|
if (event->mask & PresentIdleNotifyMask) {
|
||||||
|
in.eid = event->id;
|
||||||
|
WriteEventsToClient(event->client, 1, (xEvent *) &in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
present_select_input(ClientPtr client, XID eid, WindowPtr window, CARD32 mask)
|
||||||
|
{
|
||||||
|
present_window_priv_ptr window_priv = present_get_window_priv(window, mask != 0);
|
||||||
|
present_event_ptr event;
|
||||||
|
|
||||||
|
if (!window_priv) {
|
||||||
|
if (mask)
|
||||||
|
return BadAlloc;
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
event = calloc (1, sizeof (present_event_rec));
|
||||||
|
if (!event)
|
||||||
|
return BadAlloc;
|
||||||
|
|
||||||
|
event->client = client;
|
||||||
|
event->window = window;
|
||||||
|
event->id = eid;
|
||||||
|
event->mask = mask;
|
||||||
|
|
||||||
|
event->next = window_priv->events;
|
||||||
|
window_priv->events = event;
|
||||||
|
|
||||||
|
if (!AddResource(event->id, present_event_type, (pointer) event))
|
||||||
|
return BadAlloc;
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool
|
||||||
|
present_event_init(void)
|
||||||
|
{
|
||||||
|
present_event_type = CreateNewResourceType(present_free_event, "PresentEvent");
|
||||||
|
if (!present_event_type)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
GERegisterExtension(present_request, present_event_swap);
|
||||||
|
return TRUE;
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2013 Keith Packard
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_XORG_CONFIG_H
|
||||||
|
#include <xorg-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "present_priv.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
static struct xorg_list fake_vblank_queue;
|
||||||
|
|
||||||
|
typedef struct present_fake_vblank {
|
||||||
|
struct xorg_list list;
|
||||||
|
uint64_t event_id;
|
||||||
|
OsTimerPtr timer;
|
||||||
|
ScreenPtr screen;
|
||||||
|
} present_fake_vblank_rec, *present_fake_vblank_ptr;
|
||||||
|
|
||||||
|
int
|
||||||
|
present_fake_get_ust_msc(ScreenPtr screen, uint64_t *ust, uint64_t *msc)
|
||||||
|
{
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
*ust = GetTimeInMicros();
|
||||||
|
*msc = *ust / screen_priv->fake_interval;
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_fake_notify(ScreenPtr screen, uint64_t event_id)
|
||||||
|
{
|
||||||
|
uint64_t ust, msc;
|
||||||
|
|
||||||
|
present_fake_get_ust_msc(screen, &ust, &msc);
|
||||||
|
present_event_notify(event_id, ust, msc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CARD32
|
||||||
|
present_fake_do_timer(OsTimerPtr timer,
|
||||||
|
CARD32 time,
|
||||||
|
pointer arg)
|
||||||
|
{
|
||||||
|
present_fake_vblank_ptr fake_vblank = arg;
|
||||||
|
|
||||||
|
present_fake_notify(fake_vblank->screen, fake_vblank->event_id);
|
||||||
|
xorg_list_del(&fake_vblank->list);
|
||||||
|
free(fake_vblank);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_fake_abort_vblank(ScreenPtr screen, uint64_t event_id, uint64_t msc)
|
||||||
|
{
|
||||||
|
present_fake_vblank_ptr fake_vblank, tmp;
|
||||||
|
|
||||||
|
xorg_list_for_each_entry_safe(fake_vblank, tmp, &fake_vblank_queue, list) {
|
||||||
|
if (fake_vblank->event_id == event_id) {
|
||||||
|
TimerCancel(fake_vblank->timer);
|
||||||
|
xorg_list_del(&fake_vblank->list);
|
||||||
|
free (fake_vblank);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
present_fake_queue_vblank(ScreenPtr screen,
|
||||||
|
uint64_t event_id,
|
||||||
|
uint64_t msc)
|
||||||
|
{
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
uint64_t ust = msc * screen_priv->fake_interval;
|
||||||
|
uint64_t now = GetTimeInMicros();
|
||||||
|
INT32 delay = ((int64_t) (ust - now)) / 1000;
|
||||||
|
present_fake_vblank_ptr fake_vblank;
|
||||||
|
|
||||||
|
if (delay <= 0) {
|
||||||
|
present_fake_notify(screen, event_id);
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
fake_vblank = calloc (1, sizeof (present_fake_vblank_rec));
|
||||||
|
if (!fake_vblank)
|
||||||
|
return BadAlloc;
|
||||||
|
|
||||||
|
fake_vblank->screen = screen;
|
||||||
|
fake_vblank->event_id = event_id;
|
||||||
|
fake_vblank->timer = TimerSet(NULL, 0, delay, present_fake_do_timer, fake_vblank);
|
||||||
|
if (!fake_vblank->timer) {
|
||||||
|
free(fake_vblank);
|
||||||
|
return BadAlloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
xorg_list_add(&fake_vblank->list, &fake_vblank_queue);
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_fake_screen_init(ScreenPtr screen)
|
||||||
|
{
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
/* For screens with hardware vblank support, the fake code
|
||||||
|
* will be used for off-screen windows and while screens are blanked,
|
||||||
|
* in which case we want a slow interval here
|
||||||
|
*
|
||||||
|
* Otherwise, pretend that the screen runs at 60Hz
|
||||||
|
*/
|
||||||
|
if (screen_priv->info && screen_priv->info->get_crtc)
|
||||||
|
screen_priv->fake_interval = 1000000;
|
||||||
|
else
|
||||||
|
screen_priv->fake_interval = 16667;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_fake_queue_init(void)
|
||||||
|
{
|
||||||
|
xorg_list_init(&fake_vblank_queue);
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2013 Keith Packard
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_XORG_CONFIG_H
|
||||||
|
#include <xorg-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "present_priv.h"
|
||||||
|
#include <gcstruct.h>
|
||||||
|
#include <misync.h>
|
||||||
|
#include <misyncstr.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wraps SyncFence objects so we can add a SyncTrigger to find out
|
||||||
|
* when the SyncFence gets destroyed and clean up appropriately
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct present_fence {
|
||||||
|
SyncTrigger trigger;
|
||||||
|
SyncFence *fence;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SyncTrigger callbacks
|
||||||
|
*/
|
||||||
|
static Bool
|
||||||
|
present_fence_sync_check_trigger(SyncTrigger *trigger, XSyncValue oldval)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_fence_sync_trigger_fired(SyncTrigger *trigger)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_fence_sync_counter_destroyed(SyncTrigger *trigger)
|
||||||
|
{
|
||||||
|
struct present_fence *present_fence = container_of(trigger, struct present_fence, trigger);
|
||||||
|
|
||||||
|
present_fence->fence = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct present_fence *
|
||||||
|
present_fence_create(SyncFence *fence)
|
||||||
|
{
|
||||||
|
struct present_fence *present_fence;
|
||||||
|
|
||||||
|
present_fence = calloc (1, sizeof (struct present_fence));
|
||||||
|
if (!present_fence)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
present_fence->fence = fence;
|
||||||
|
present_fence->trigger.pSync = (SyncObject *) fence;
|
||||||
|
present_fence->trigger.CheckTrigger = present_fence_sync_check_trigger;
|
||||||
|
present_fence->trigger.TriggerFired = present_fence_sync_trigger_fired;
|
||||||
|
present_fence->trigger.CounterDestroyed = present_fence_sync_counter_destroyed;
|
||||||
|
|
||||||
|
if (SyncAddTriggerToSyncObject(&present_fence->trigger) != Success) {
|
||||||
|
free (present_fence);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return present_fence;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_fence_destroy(struct present_fence *present_fence)
|
||||||
|
{
|
||||||
|
if (present_fence) {
|
||||||
|
if (present_fence->fence)
|
||||||
|
SyncDeleteTriggerFromSyncObject(&present_fence->trigger);
|
||||||
|
free(present_fence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_fence_set_triggered(struct present_fence *present_fence)
|
||||||
|
{
|
||||||
|
if (present_fence)
|
||||||
|
if (present_fence->fence)
|
||||||
|
(*present_fence->fence->funcs.SetTriggered) (present_fence->fence);
|
||||||
|
}
|
||||||
|
|
||||||
|
XID
|
||||||
|
present_fence_id(struct present_fence *present_fence)
|
||||||
|
{
|
||||||
|
if (!present_fence)
|
||||||
|
return None;
|
||||||
|
if (!present_fence->fence)
|
||||||
|
return None;
|
||||||
|
return present_fence->fence->sync.id;
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2013 Keith Packard
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_XORG_CONFIG_H
|
||||||
|
#include <xorg-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "present_priv.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark all pending notifies for 'window' as invalid when
|
||||||
|
* the window is destroyed
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
present_clear_window_notifies(WindowPtr window)
|
||||||
|
{
|
||||||
|
present_notify_ptr notify;
|
||||||
|
present_window_priv_ptr window_priv = present_window_priv(window);
|
||||||
|
|
||||||
|
if (!window_priv)
|
||||||
|
return;
|
||||||
|
|
||||||
|
xorg_list_for_each_entry(notify, &window_priv->notifies, window_list) {
|
||||||
|
notify->window = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'notify' is being freed; remove it from the window's notify list
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
present_free_window_notify(present_notify_ptr notify)
|
||||||
|
{
|
||||||
|
xorg_list_del(¬ify->window_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'notify' is new; add it to the specified window
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
present_add_window_notify(present_notify_ptr notify)
|
||||||
|
{
|
||||||
|
WindowPtr window = notify->window;
|
||||||
|
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
|
||||||
|
|
||||||
|
if (!window_priv)
|
||||||
|
return BadAlloc;
|
||||||
|
|
||||||
|
xorg_list_add(¬ify->window_list, &window_priv->notifies);
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
present_create_notifies(ClientPtr client, int num_notifies, xPresentNotify *x_notifies, present_notify_ptr *p_notifies)
|
||||||
|
{
|
||||||
|
present_notify_ptr notifies;
|
||||||
|
int i;
|
||||||
|
int added = 0;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
notifies = calloc (num_notifies, sizeof (present_notify_rec));
|
||||||
|
if (!notifies)
|
||||||
|
return BadAlloc;
|
||||||
|
|
||||||
|
for (i = 0; i < num_notifies; i++) {
|
||||||
|
status = dixLookupWindow(¬ifies[i].window, x_notifies[i].window, client, DixGetAttrAccess);
|
||||||
|
if (status != Success)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
notifies[i].serial = x_notifies[i].serial;
|
||||||
|
status = present_add_window_notify(¬ifies[i]);
|
||||||
|
if (status != Success)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
added = i;
|
||||||
|
}
|
||||||
|
return Success;
|
||||||
|
|
||||||
|
bail:
|
||||||
|
present_destroy_notifies(notifies, added);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
present_destroy_notifies(present_notify_ptr notifies, int num_notifies)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < num_notifies; i++)
|
||||||
|
present_free_window_notify(¬ifies[i]);
|
||||||
|
|
||||||
|
free(notifies);
|
||||||
|
}
|
|
@ -0,0 +1,288 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2013 Keith Packard
|
||||||
|
*
|
||||||
|
* 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 _PRESENT_PRIV_H_
|
||||||
|
#define _PRESENT_PRIV_H_
|
||||||
|
|
||||||
|
#include <X11/X.h>
|
||||||
|
#include "scrnintstr.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "windowstr.h"
|
||||||
|
#include "dixstruct.h"
|
||||||
|
#include "present.h"
|
||||||
|
#include <syncsdk.h>
|
||||||
|
#include <syncsrv.h>
|
||||||
|
#include <xfixes.h>
|
||||||
|
#include <randrstr.h>
|
||||||
|
|
||||||
|
extern int present_request;
|
||||||
|
|
||||||
|
extern DevPrivateKeyRec present_screen_private_key;
|
||||||
|
|
||||||
|
typedef struct present_fence *present_fence_ptr;
|
||||||
|
|
||||||
|
typedef struct present_notify present_notify_rec, *present_notify_ptr;
|
||||||
|
|
||||||
|
struct present_notify {
|
||||||
|
struct xorg_list window_list;
|
||||||
|
WindowPtr window;
|
||||||
|
CARD32 serial;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct present_vblank {
|
||||||
|
struct xorg_list window_list;
|
||||||
|
struct xorg_list event_queue;
|
||||||
|
ScreenPtr screen;
|
||||||
|
WindowPtr window;
|
||||||
|
PixmapPtr pixmap;
|
||||||
|
RegionPtr valid;
|
||||||
|
RegionPtr update;
|
||||||
|
RRCrtcPtr crtc;
|
||||||
|
uint32_t serial;
|
||||||
|
int16_t x_off;
|
||||||
|
int16_t y_off;
|
||||||
|
CARD16 kind;
|
||||||
|
uint64_t event_id;
|
||||||
|
uint64_t target_msc;
|
||||||
|
uint64_t msc_offset;
|
||||||
|
present_fence_ptr idle_fence;
|
||||||
|
present_fence_ptr wait_fence;
|
||||||
|
present_notify_ptr notifies;
|
||||||
|
int num_notifies;
|
||||||
|
Bool flip;
|
||||||
|
Bool sync_flip;
|
||||||
|
Bool abort_flip;
|
||||||
|
|
||||||
|
Bool window_destroyed;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct present_screen_priv {
|
||||||
|
CloseScreenProcPtr CloseScreen;
|
||||||
|
ConfigNotifyProcPtr ConfigNotify;
|
||||||
|
DestroyWindowProcPtr DestroyWindow;
|
||||||
|
ClipNotifyProcPtr ClipNotify;
|
||||||
|
|
||||||
|
present_vblank_ptr flip_pending;
|
||||||
|
uint64_t unflip_event_id;
|
||||||
|
|
||||||
|
uint32_t fake_interval;
|
||||||
|
|
||||||
|
/* Currently active flipped pixmap and fence */
|
||||||
|
RRCrtcPtr flip_crtc;
|
||||||
|
WindowPtr flip_window;
|
||||||
|
uint32_t flip_serial;
|
||||||
|
PixmapPtr flip_pixmap;
|
||||||
|
present_fence_ptr flip_idle_fence;
|
||||||
|
|
||||||
|
present_screen_info_ptr info;
|
||||||
|
} present_screen_priv_rec, *present_screen_priv_ptr;
|
||||||
|
|
||||||
|
#define wrap(priv,real,mem,func) {\
|
||||||
|
priv->mem = real->mem; \
|
||||||
|
real->mem = func; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define unwrap(priv,real,mem) {\
|
||||||
|
real->mem = priv->mem; \
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline present_screen_priv_ptr
|
||||||
|
present_screen_priv(ScreenPtr screen)
|
||||||
|
{
|
||||||
|
return (present_screen_priv_ptr)dixLookupPrivate(&(screen)->devPrivates, &present_screen_private_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each window has a list of clients and event masks
|
||||||
|
*/
|
||||||
|
typedef struct present_event *present_event_ptr;
|
||||||
|
|
||||||
|
typedef struct present_event {
|
||||||
|
present_event_ptr next;
|
||||||
|
ClientPtr client;
|
||||||
|
WindowPtr window;
|
||||||
|
XID id;
|
||||||
|
int mask;
|
||||||
|
} present_event_rec;
|
||||||
|
|
||||||
|
typedef struct present_window_priv {
|
||||||
|
present_event_ptr events;
|
||||||
|
RRCrtcPtr crtc; /* Last reported CRTC from get_ust_msc */
|
||||||
|
uint64_t msc_offset;
|
||||||
|
uint64_t msc; /* Last reported MSC from the current crtc */
|
||||||
|
struct xorg_list vblank;
|
||||||
|
struct xorg_list notifies;
|
||||||
|
} present_window_priv_rec, *present_window_priv_ptr;
|
||||||
|
|
||||||
|
extern DevPrivateKeyRec present_window_private_key;
|
||||||
|
|
||||||
|
static inline present_window_priv_ptr
|
||||||
|
present_window_priv(WindowPtr window)
|
||||||
|
{
|
||||||
|
return (present_window_priv_ptr)dixGetPrivate(&(window)->devPrivates, &present_window_private_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
present_window_priv_ptr
|
||||||
|
present_get_window_priv(WindowPtr window, Bool create);
|
||||||
|
|
||||||
|
extern RESTYPE present_event_type;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* present.c
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
present_pixmap(WindowPtr window,
|
||||||
|
PixmapPtr pixmap,
|
||||||
|
CARD32 serial,
|
||||||
|
RegionPtr valid,
|
||||||
|
RegionPtr update,
|
||||||
|
int16_t x_off,
|
||||||
|
int16_t y_off,
|
||||||
|
RRCrtcPtr target_crtc,
|
||||||
|
SyncFence *wait_fence,
|
||||||
|
SyncFence *idle_fence,
|
||||||
|
uint32_t options,
|
||||||
|
uint64_t target_msc,
|
||||||
|
uint64_t divisor,
|
||||||
|
uint64_t remainder,
|
||||||
|
present_notify_ptr notifies,
|
||||||
|
int num_notifies);
|
||||||
|
|
||||||
|
int
|
||||||
|
present_notify_msc(WindowPtr window,
|
||||||
|
CARD32 serial,
|
||||||
|
uint64_t target_msc,
|
||||||
|
uint64_t divisor,
|
||||||
|
uint64_t remainder);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_abort_vblank(ScreenPtr screen, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_vblank_destroy(present_vblank_ptr vblank);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_flip_destroy(ScreenPtr screen);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_check_flip_window(WindowPtr window);
|
||||||
|
|
||||||
|
RRCrtcPtr
|
||||||
|
present_get_crtc(WindowPtr window);
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
present_query_capabilities(RRCrtcPtr crtc);
|
||||||
|
|
||||||
|
Bool
|
||||||
|
present_init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* present_event.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
present_free_events(WindowPtr window);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_send_config_notify(WindowPtr window, int x, int y, int w, int h, int bw, WindowPtr sibling);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_send_complete_notify(WindowPtr window, CARD8 kind, CARD8 mode, CARD32 serial, uint64_t ust, uint64_t msc);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_send_idle_notify(WindowPtr window, CARD32 serial, PixmapPtr pixmap, present_fence_ptr idle_fence);
|
||||||
|
|
||||||
|
int
|
||||||
|
present_select_input(ClientPtr client,
|
||||||
|
CARD32 eid,
|
||||||
|
WindowPtr window,
|
||||||
|
CARD32 event_mask);
|
||||||
|
|
||||||
|
Bool
|
||||||
|
present_event_init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* present_fake.c
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
present_fake_get_ust_msc(ScreenPtr screen, uint64_t *ust, uint64_t *msc);
|
||||||
|
|
||||||
|
int
|
||||||
|
present_fake_queue_vblank(ScreenPtr screen, uint64_t event_id, uint64_t msc);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_fake_abort_vblank(ScreenPtr screen, uint64_t event_id, uint64_t msc);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_fake_screen_init(ScreenPtr screen);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_fake_queue_init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* present_fence.c
|
||||||
|
*/
|
||||||
|
struct present_fence *
|
||||||
|
present_fence_create(SyncFence *sync_fence);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_fence_destroy(struct present_fence *present_fence);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_fence_set_triggered(struct present_fence *present_fence);
|
||||||
|
|
||||||
|
XID
|
||||||
|
present_fence_id(struct present_fence *present_fence);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* present_notify.c
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
present_clear_window_notifies(WindowPtr window);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_free_window_notify(present_notify_ptr notify);
|
||||||
|
|
||||||
|
int
|
||||||
|
present_add_window_notify(present_notify_ptr notify);
|
||||||
|
|
||||||
|
int
|
||||||
|
present_create_notifies(ClientPtr client, int num_notifies, xPresentNotify *x_notifies, present_notify_ptr *p_notifies);
|
||||||
|
|
||||||
|
void
|
||||||
|
present_destroy_notifies(present_notify_ptr notifies, int num_notifies);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* present_request.c
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
proc_present_dispatch(ClientPtr client);
|
||||||
|
|
||||||
|
int
|
||||||
|
sproc_present_dispatch(ClientPtr client);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* present_screen.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif /* _PRESENT_PRIV_H_ */
|
|
@ -0,0 +1,330 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2013 Keith Packard
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_XORG_CONFIG_H
|
||||||
|
#include <xorg-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "present_priv.h"
|
||||||
|
#include "randrstr.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
proc_present_query_version(ClientPtr client)
|
||||||
|
{
|
||||||
|
REQUEST(xPresentQueryVersionReq);
|
||||||
|
xPresentQueryVersionReply rep = {
|
||||||
|
.type = X_Reply,
|
||||||
|
.sequenceNumber = client->sequence,
|
||||||
|
.length = 0,
|
||||||
|
.majorVersion = PRESENT_MAJOR,
|
||||||
|
.minorVersion = PRESENT_MINOR
|
||||||
|
};
|
||||||
|
|
||||||
|
REQUEST_SIZE_MATCH(xPresentQueryVersionReq);
|
||||||
|
(void) stuff;
|
||||||
|
if (client->swapped) {
|
||||||
|
swaps(&rep.sequenceNumber);
|
||||||
|
swapl(&rep.length);
|
||||||
|
swapl(&rep.majorVersion);
|
||||||
|
swapl(&rep.minorVersion);
|
||||||
|
}
|
||||||
|
WriteToClient(client, sizeof(rep), &rep);
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VERIFY_FENCE_OR_NONE(fence_ptr, fence_id, client, access) do { \
|
||||||
|
if ((fence_id) == None) \
|
||||||
|
(fence_ptr) = NULL; \
|
||||||
|
else { \
|
||||||
|
int __rc__ = SyncVerifyFence(&fence_ptr, fence_id, client, access); \
|
||||||
|
if (__rc__ != Success) \
|
||||||
|
return __rc__; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define VERIFY_CRTC_OR_NONE(crtc_ptr, crtc_id, client, access) do { \
|
||||||
|
if ((crtc_id) == None) \
|
||||||
|
(crtc_ptr) = NULL; \
|
||||||
|
else { \
|
||||||
|
VERIFY_RR_CRTC(crtc_id, crtc_ptr, access); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static int
|
||||||
|
proc_present_pixmap(ClientPtr client)
|
||||||
|
{
|
||||||
|
REQUEST(xPresentPixmapReq);
|
||||||
|
WindowPtr window;
|
||||||
|
PixmapPtr pixmap;
|
||||||
|
RegionPtr valid = NULL;
|
||||||
|
RegionPtr update = NULL;
|
||||||
|
SyncFence *wait_fence;
|
||||||
|
SyncFence *idle_fence;
|
||||||
|
RRCrtcPtr target_crtc;
|
||||||
|
int ret;
|
||||||
|
int nnotifies;
|
||||||
|
present_notify_ptr notifies = NULL;
|
||||||
|
|
||||||
|
REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
|
||||||
|
ret = dixLookupWindow(&window, stuff->window, client, DixWriteAccess);
|
||||||
|
if (ret != Success)
|
||||||
|
return ret;
|
||||||
|
ret = dixLookupResourceByType((pointer *) &pixmap, stuff->pixmap, RT_PIXMAP, client, DixReadAccess);
|
||||||
|
if (ret != Success)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (window->drawable.depth != pixmap->drawable.depth)
|
||||||
|
return BadMatch;
|
||||||
|
|
||||||
|
VERIFY_REGION_OR_NONE(valid, stuff->valid, client, DixReadAccess);
|
||||||
|
VERIFY_REGION_OR_NONE(update, stuff->update, client, DixReadAccess);
|
||||||
|
|
||||||
|
VERIFY_CRTC_OR_NONE(target_crtc, stuff->target_crtc, client, DixReadAccess);
|
||||||
|
|
||||||
|
VERIFY_FENCE_OR_NONE(wait_fence, stuff->wait_fence, client, DixReadAccess);
|
||||||
|
VERIFY_FENCE_OR_NONE(idle_fence, stuff->idle_fence, client, DixWriteAccess);
|
||||||
|
|
||||||
|
if (stuff->options & ~(PresentAllOptions)) {
|
||||||
|
client->errorValue = stuff->options;
|
||||||
|
return BadValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check to see if remainder is sane
|
||||||
|
*/
|
||||||
|
if (stuff->divisor == 0) {
|
||||||
|
if (stuff->remainder != 0) {
|
||||||
|
client->errorValue = (CARD32) stuff->remainder;
|
||||||
|
return BadValue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (stuff->remainder >= stuff->divisor) {
|
||||||
|
client->errorValue = (CARD32) stuff->remainder;
|
||||||
|
return BadValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nnotifies = (client->req_len << 2) - sizeof (xPresentPixmapReq);
|
||||||
|
if (nnotifies % sizeof (xPresentNotify))
|
||||||
|
return BadLength;
|
||||||
|
|
||||||
|
nnotifies /= sizeof (xPresentNotify);
|
||||||
|
if (nnotifies) {
|
||||||
|
ret = present_create_notifies(client, nnotifies, (xPresentNotify *) (stuff + 1), ¬ifies);
|
||||||
|
if (ret != Success)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = present_pixmap(window, pixmap, stuff->serial, valid, update,
|
||||||
|
stuff->x_off, stuff->y_off, target_crtc,
|
||||||
|
wait_fence, idle_fence, stuff->options,
|
||||||
|
stuff->target_msc, stuff->divisor, stuff->remainder, notifies, nnotifies);
|
||||||
|
if (ret != Success)
|
||||||
|
present_destroy_notifies(notifies, nnotifies);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
proc_present_notify_msc(ClientPtr client)
|
||||||
|
{
|
||||||
|
REQUEST(xPresentNotifyMSCReq);
|
||||||
|
WindowPtr window;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
REQUEST_SIZE_MATCH(xPresentNotifyMSCReq);
|
||||||
|
rc = dixLookupWindow(&window, stuff->window, client, DixReadAccess);
|
||||||
|
if (rc != Success)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check to see if remainder is sane
|
||||||
|
*/
|
||||||
|
if (stuff->divisor == 0) {
|
||||||
|
if (stuff->remainder != 0) {
|
||||||
|
client->errorValue = (CARD32) stuff->remainder;
|
||||||
|
return BadValue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (stuff->remainder >= stuff->divisor) {
|
||||||
|
client->errorValue = (CARD32) stuff->remainder;
|
||||||
|
return BadValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return present_notify_msc(window, stuff->serial,
|
||||||
|
stuff->target_msc, stuff->divisor, stuff->remainder);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
proc_present_select_input (ClientPtr client)
|
||||||
|
{
|
||||||
|
REQUEST(xPresentSelectInputReq);
|
||||||
|
WindowPtr window;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
REQUEST_SIZE_MATCH(xPresentSelectInputReq);
|
||||||
|
|
||||||
|
LEGAL_NEW_RESOURCE(stuff->eid, client);
|
||||||
|
|
||||||
|
rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
|
||||||
|
if (rc != Success)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (stuff->eventMask & ~PresentAllEvents) {
|
||||||
|
client->errorValue = stuff->eventMask;
|
||||||
|
return BadValue;
|
||||||
|
}
|
||||||
|
return present_select_input(client, stuff->eid, window, stuff->eventMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
proc_present_query_capabilities (ClientPtr client)
|
||||||
|
{
|
||||||
|
REQUEST(xPresentQueryCapabilitiesReq);
|
||||||
|
xPresentQueryCapabilitiesReply rep = {
|
||||||
|
.type = X_Reply,
|
||||||
|
.sequenceNumber = client->sequence,
|
||||||
|
.length = 0,
|
||||||
|
};
|
||||||
|
WindowPtr window;
|
||||||
|
RRCrtcPtr crtc = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = dixLookupWindow(&window, stuff->target, client, DixGetAttrAccess);
|
||||||
|
switch (r) {
|
||||||
|
case Success:
|
||||||
|
crtc = present_get_crtc(window);
|
||||||
|
break;
|
||||||
|
case BadWindow:
|
||||||
|
VERIFY_RR_CRTC(stuff->target, crtc, DixGetAttrAccess);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
rep.capabilities = present_query_capabilities(crtc);
|
||||||
|
|
||||||
|
if (client->swapped) {
|
||||||
|
swaps(&rep.sequenceNumber);
|
||||||
|
swapl(&rep.length);
|
||||||
|
swapl(&rep.capabilities);
|
||||||
|
}
|
||||||
|
WriteToClient(client, sizeof(rep), &rep);
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int (*proc_present_vector[PresentNumberRequests]) (ClientPtr) = {
|
||||||
|
proc_present_query_version, /* 0 */
|
||||||
|
proc_present_pixmap, /* 1 */
|
||||||
|
proc_present_notify_msc, /* 2 */
|
||||||
|
proc_present_select_input, /* 3 */
|
||||||
|
proc_present_query_capabilities, /* 4 */
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
proc_present_dispatch(ClientPtr client)
|
||||||
|
{
|
||||||
|
REQUEST(xReq);
|
||||||
|
if (stuff->data >= PresentNumberRequests || !proc_present_vector[stuff->data])
|
||||||
|
return BadRequest;
|
||||||
|
return (*proc_present_vector[stuff->data]) (client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sproc_present_query_version(ClientPtr client)
|
||||||
|
{
|
||||||
|
REQUEST(xPresentQueryVersionReq);
|
||||||
|
|
||||||
|
swaps(&stuff->length);
|
||||||
|
swapl(&stuff->majorVersion);
|
||||||
|
swapl(&stuff->minorVersion);
|
||||||
|
return (*proc_present_vector[stuff->presentReqType]) (client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sproc_present_pixmap(ClientPtr client)
|
||||||
|
{
|
||||||
|
REQUEST(xPresentPixmapReq);
|
||||||
|
|
||||||
|
swaps(&stuff->length);
|
||||||
|
swapl(&stuff->window);
|
||||||
|
swapl(&stuff->pixmap);
|
||||||
|
swapl(&stuff->valid);
|
||||||
|
swapl(&stuff->update);
|
||||||
|
swaps(&stuff->x_off);
|
||||||
|
swaps(&stuff->y_off);
|
||||||
|
swapll(&stuff->target_msc);
|
||||||
|
swapll(&stuff->divisor);
|
||||||
|
swapll(&stuff->remainder);
|
||||||
|
swapl(&stuff->idle_fence);
|
||||||
|
return (*proc_present_vector[stuff->presentReqType]) (client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sproc_present_notify_msc(ClientPtr client)
|
||||||
|
{
|
||||||
|
REQUEST(xPresentNotifyMSCReq);
|
||||||
|
|
||||||
|
swaps(&stuff->length);
|
||||||
|
swapl(&stuff->window);
|
||||||
|
swapll(&stuff->target_msc);
|
||||||
|
swapll(&stuff->divisor);
|
||||||
|
swapll(&stuff->remainder);
|
||||||
|
return (*proc_present_vector[stuff->presentReqType]) (client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sproc_present_select_input (ClientPtr client)
|
||||||
|
{
|
||||||
|
REQUEST(xPresentSelectInputReq);
|
||||||
|
|
||||||
|
swaps(&stuff->length);
|
||||||
|
swapl(&stuff->window);
|
||||||
|
swapl(&stuff->eventMask);
|
||||||
|
return (*proc_present_vector[stuff->presentReqType]) (client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
sproc_present_query_capabilities (ClientPtr client)
|
||||||
|
{
|
||||||
|
REQUEST(xPresentQueryCapabilitiesReq);
|
||||||
|
swaps(&stuff->length);
|
||||||
|
swapl(&stuff->target);
|
||||||
|
return (*proc_present_vector[stuff->presentReqType]) (client);
|
||||||
|
}
|
||||||
|
|
||||||
|
int (*sproc_present_vector[PresentNumberRequests]) (ClientPtr) = {
|
||||||
|
sproc_present_query_version, /* 0 */
|
||||||
|
sproc_present_pixmap, /* 1 */
|
||||||
|
sproc_present_notify_msc, /* 2 */
|
||||||
|
sproc_present_select_input, /* 3 */
|
||||||
|
sproc_present_query_capabilities, /* 4 */
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
sproc_present_dispatch(ClientPtr client)
|
||||||
|
{
|
||||||
|
REQUEST(xReq);
|
||||||
|
if (stuff->data >= PresentNumberRequests || !sproc_present_vector[stuff->data])
|
||||||
|
return BadRequest;
|
||||||
|
return (*sproc_present_vector[stuff->data]) (client);
|
||||||
|
}
|
|
@ -0,0 +1,231 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2013 Keith Packard
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_XORG_CONFIG_H
|
||||||
|
#include <xorg-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "present_priv.h"
|
||||||
|
|
||||||
|
int present_request;
|
||||||
|
DevPrivateKeyRec present_screen_private_key;
|
||||||
|
DevPrivateKeyRec present_window_private_key;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a pointer to a present window private, creating if necessary
|
||||||
|
*/
|
||||||
|
present_window_priv_ptr
|
||||||
|
present_get_window_priv(WindowPtr window, Bool create)
|
||||||
|
{
|
||||||
|
present_window_priv_ptr window_priv = present_window_priv(window);
|
||||||
|
|
||||||
|
if (!create || window_priv != NULL)
|
||||||
|
return window_priv;
|
||||||
|
window_priv = calloc (1, sizeof (present_window_priv_rec));
|
||||||
|
if (!window_priv)
|
||||||
|
return NULL;
|
||||||
|
xorg_list_init(&window_priv->vblank);
|
||||||
|
xorg_list_init(&window_priv->notifies);
|
||||||
|
dixSetPrivate(&window->devPrivates, &present_window_private_key, window_priv);
|
||||||
|
return window_priv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hook the close screen function to clean up our screen private
|
||||||
|
*/
|
||||||
|
static Bool
|
||||||
|
present_close_screen(ScreenPtr screen)
|
||||||
|
{
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
present_flip_destroy(screen);
|
||||||
|
|
||||||
|
unwrap(screen_priv, screen, CloseScreen);
|
||||||
|
(*screen->CloseScreen) (screen);
|
||||||
|
free(screen_priv);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free any queued presentations for this window
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
present_free_window_vblank(WindowPtr window)
|
||||||
|
{
|
||||||
|
present_window_priv_ptr window_priv = present_window_priv(window);
|
||||||
|
present_vblank_ptr vblank, tmp;
|
||||||
|
|
||||||
|
xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
|
||||||
|
present_abort_vblank(window->drawable.pScreen, vblank->crtc, vblank->event_id, vblank->target_msc);
|
||||||
|
present_vblank_destroy(vblank);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clean up any pending or current flips for this window
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
present_clear_window_flip(WindowPtr window)
|
||||||
|
{
|
||||||
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
present_vblank_ptr flip_pending = screen_priv->flip_pending;
|
||||||
|
|
||||||
|
if (flip_pending && flip_pending->window == window) {
|
||||||
|
assert (flip_pending->abort_flip);
|
||||||
|
flip_pending->window_destroyed = TRUE;
|
||||||
|
}
|
||||||
|
if (screen_priv->flip_window == window)
|
||||||
|
screen_priv->flip_window = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hook the close window function to clean up our window private
|
||||||
|
*/
|
||||||
|
static Bool
|
||||||
|
present_destroy_window(WindowPtr window)
|
||||||
|
{
|
||||||
|
Bool ret;
|
||||||
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
present_window_priv_ptr window_priv = present_window_priv(window);
|
||||||
|
|
||||||
|
if (window_priv) {
|
||||||
|
present_clear_window_notifies(window);
|
||||||
|
present_free_events(window);
|
||||||
|
present_free_window_vblank(window);
|
||||||
|
present_clear_window_flip(window);
|
||||||
|
free(window_priv);
|
||||||
|
}
|
||||||
|
unwrap(screen_priv, screen, DestroyWindow);
|
||||||
|
if (screen->DestroyWindow)
|
||||||
|
ret = screen->DestroyWindow (window);
|
||||||
|
else
|
||||||
|
ret = TRUE;
|
||||||
|
wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hook the config notify screen function to deliver present config notify events
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
present_config_notify(WindowPtr window,
|
||||||
|
int x, int y, int w, int h, int bw,
|
||||||
|
WindowPtr sibling)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
present_send_config_notify(window, x, y, w, h, bw, sibling);
|
||||||
|
|
||||||
|
unwrap(screen_priv, screen, ConfigNotify);
|
||||||
|
if (screen->ConfigNotify)
|
||||||
|
ret = screen->ConfigNotify (window, x, y, w, h, bw, sibling);
|
||||||
|
else
|
||||||
|
ret = 0;
|
||||||
|
wrap(screen_priv, screen, ConfigNotify, present_config_notify);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hook the clip notify screen function to un-flip as necessary
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_clip_notify(WindowPtr window, int dx, int dy)
|
||||||
|
{
|
||||||
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
present_check_flip_window(window);
|
||||||
|
unwrap(screen_priv, screen, ClipNotify)
|
||||||
|
if (screen->ClipNotify)
|
||||||
|
screen->ClipNotify (window, dx, dy);
|
||||||
|
wrap(screen_priv, screen, ClipNotify, present_clip_notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize a screen for use with present
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
present_screen_init(ScreenPtr screen, present_screen_info_ptr info)
|
||||||
|
{
|
||||||
|
if (!dixRegisterPrivateKey(&present_screen_private_key, PRIVATE_SCREEN, 0))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!dixRegisterPrivateKey(&present_window_private_key, PRIVATE_WINDOW, 0))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!present_screen_priv(screen)) {
|
||||||
|
present_screen_priv_ptr screen_priv = calloc(1, sizeof (present_screen_priv_rec));
|
||||||
|
if (!screen_priv)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
wrap(screen_priv, screen, CloseScreen, present_close_screen);
|
||||||
|
wrap(screen_priv, screen, DestroyWindow, present_destroy_window);
|
||||||
|
wrap(screen_priv, screen, ConfigNotify, present_config_notify);
|
||||||
|
wrap(screen_priv, screen, ClipNotify, present_clip_notify);
|
||||||
|
|
||||||
|
screen_priv->info = info;
|
||||||
|
|
||||||
|
dixSetPrivate(&screen->devPrivates, &present_screen_private_key, screen_priv);
|
||||||
|
|
||||||
|
present_fake_screen_init(screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the present extension
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
present_extension_init(void)
|
||||||
|
{
|
||||||
|
ExtensionEntry *extension;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
extension = AddExtension(PRESENT_NAME, PresentNumberEvents, PresentNumberErrors,
|
||||||
|
proc_present_dispatch, sproc_present_dispatch,
|
||||||
|
NULL, StandardMinorOpcode);
|
||||||
|
if (!extension)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
present_request = extension->base;
|
||||||
|
|
||||||
|
if (!present_init())
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
if (!present_event_init())
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
for (i = 0; i < screenInfo.numScreens; i++) {
|
||||||
|
if (!present_screen_init(screenInfo.screens[i], NULL))
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
bail:
|
||||||
|
FatalError("Cannot initialize Present extension");
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2013 Keith Packard
|
||||||
|
*
|
||||||
|
* 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 _PRESENTEXT_H_
|
||||||
|
#define _PRESENTEXT_H_
|
||||||
|
|
||||||
|
extern _X_EXPORT void
|
||||||
|
present_extension_init(void);
|
||||||
|
|
||||||
|
#endif /* _PRESENTEXT_H_ */
|
Loading…
Reference in New Issue