diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2019-07-27 07:57:27 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2019-07-27 07:57:27 +0000 |
commit | d4a0bed4b91da9de86c311c7fef9a8aa9a6f500c (patch) | |
tree | a1b439049dee87bc951e190db93f5bbe8b43b0b5 /xserver/hw/xwayland | |
parent | b6bc775539a31f663f9e22ce3ccaf0aa96adf3b6 (diff) |
Update to xserver 1.20.5. Tested by jsg@
Diffstat (limited to 'xserver/hw/xwayland')
-rw-r--r-- | xserver/hw/xwayland/Makefile.am | 65 | ||||
-rw-r--r-- | xserver/hw/xwayland/Makefile.in | 277 | ||||
-rw-r--r-- | xserver/hw/xwayland/xwayland-cursor.c | 95 | ||||
-rw-r--r-- | xserver/hw/xwayland/xwayland-glamor-eglstream.c | 932 | ||||
-rw-r--r-- | xserver/hw/xwayland/xwayland-glamor-gbm.c | 1035 | ||||
-rw-r--r-- | xserver/hw/xwayland/xwayland-glamor-xv.c | 2 | ||||
-rw-r--r-- | xserver/hw/xwayland/xwayland-glamor.c | 582 | ||||
-rw-r--r-- | xserver/hw/xwayland/xwayland-input.c | 1305 | ||||
-rw-r--r-- | xserver/hw/xwayland/xwayland-output.c | 147 | ||||
-rw-r--r-- | xserver/hw/xwayland/xwayland-present.c | 578 | ||||
-rw-r--r-- | xserver/hw/xwayland/xwayland-shm.c | 2 | ||||
-rw-r--r-- | xserver/hw/xwayland/xwayland.c | 343 | ||||
-rw-r--r-- | xserver/hw/xwayland/xwayland.h | 280 |
13 files changed, 5000 insertions, 643 deletions
diff --git a/xserver/hw/xwayland/Makefile.am b/xserver/hw/xwayland/Makefile.am index a3c9fce48..bc1cb8506 100644 --- a/xserver/hw/xwayland/Makefile.am +++ b/xserver/hw/xwayland/Makefile.am @@ -18,13 +18,13 @@ Xwayland_SOURCES = \ xwayland-cvt.c \ xwayland-vidmode.c \ xwayland.h \ - $(top_srcdir)/Xext/dpmsstubs.c \ $(top_srcdir)/Xi/stubs.c \ $(top_srcdir)/mi/miinitext.c Xwayland_LDADD = \ $(glamor_lib) \ $(XWAYLAND_LIBS) \ + $(top_builddir)/glx/libglxvnd.la \ $(XWAYLAND_SYS_LIBS) \ $(top_builddir)/Xext/libXvidmode.la \ $(XSERVER_SYS_LIBS) @@ -34,12 +34,19 @@ Xwayland_built_sources = if GLAMOR_EGL Xwayland_SOURCES += \ - xwayland-glamor.c + xwayland-glamor.c \ + xwayland-glamor-gbm.c \ + xwayland-present.c if XV Xwayland_SOURCES += \ xwayland-glamor-xv.c endif +if XWAYLAND_EGLSTREAM +Xwayland_SOURCES += \ + xwayland-glamor-eglstream.c +endif + glamor_built_sources = \ drm-client-protocol.h \ drm-protocol.c @@ -56,31 +63,75 @@ Xwayland_built_sources += \ relative-pointer-unstable-v1-client-protocol.h \ relative-pointer-unstable-v1-protocol.c \ pointer-constraints-unstable-v1-client-protocol.h \ - pointer-constraints-unstable-v1-protocol.c + pointer-constraints-unstable-v1-protocol.c \ + tablet-unstable-v2-client-protocol.h \ + tablet-unstable-v2-protocol.c \ + xwayland-keyboard-grab-unstable-v1-protocol.c \ + xwayland-keyboard-grab-unstable-v1-client-protocol.h \ + xdg-output-unstable-v1-protocol.c \ + xdg-output-unstable-v1-client-protocol.h \ + linux-dmabuf-unstable-v1-client-protocol.h \ + linux-dmabuf-unstable-v1-protocol.c + +if XWAYLAND_EGLSTREAM +Xwayland_built_sources += \ + wayland-eglstream-client-protocol.h \ + wayland-eglstream-protocol.c \ + wayland-eglstream-controller-client-protocol.h \ + wayland-eglstream-controller-protocol.c +endif nodist_Xwayland_SOURCES = $(Xwayland_built_sources) CLEANFILES = $(Xwayland_built_sources) EXTRA_DIST = drm.xml - $(Xwayland_SOURCES): $(Xwayland_built_sources) relink: $(AM_V_at)rm -f Xwayland$(EXEEXT) && $(MAKE) Xwayland$(EXEEXT) relative-pointer-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/relative-pointer/relative-pointer-unstable-v1.xml - $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ relative-pointer-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/relative-pointer/relative-pointer-unstable-v1.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ pointer-constraints-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml - $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ pointer-constraints-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ -%-protocol.c : %.xml +tablet-unstable-v2-protocol.c: $(WAYLAND_PROTOCOLS_DATADIR)/unstable/tablet/tablet-unstable-v2.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ +tablet-unstable-v2-client-protocol.h: $(WAYLAND_PROTOCOLS_DATADIR)/unstable/tablet/tablet-unstable-v2.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ + +xwayland-keyboard-grab-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xwayland-keyboard-grab/xwayland-keyboard-grab-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ +xwayland-keyboard-grab-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xwayland-keyboard-grab/xwayland-keyboard-grab-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ +xdg-output-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xdg-output/xdg-output-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ +xdg-output-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xdg-output/xdg-output-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ + +linux-dmabuf-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ +linux-dmabuf-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ + +wayland-eglstream-client-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ +wayland-eglstream-controller-client-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream-controller.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ + +wayland-eglstream-protocol.c : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ +wayland-eglstream-controller-protocol.c : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream-controller.xml $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ +%-protocol.c : %.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ + %-client-protocol.h : %.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ diff --git a/xserver/hw/xwayland/Makefile.in b/xserver/hw/xwayland/Makefile.in index 7b9a37e89..5a110e736 100644 --- a/xserver/hw/xwayland/Makefile.in +++ b/xserver/hw/xwayland/Makefile.in @@ -52,17 +52,30 @@ build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = Xwayland$(EXEEXT) @GLAMOR_EGL_TRUE@am__append_1 = \ -@GLAMOR_EGL_TRUE@ xwayland-glamor.c +@GLAMOR_EGL_TRUE@ xwayland-glamor.c \ +@GLAMOR_EGL_TRUE@ xwayland-glamor-gbm.c \ +@GLAMOR_EGL_TRUE@ xwayland-present.c @GLAMOR_EGL_TRUE@@XV_TRUE@am__append_2 = \ @GLAMOR_EGL_TRUE@@XV_TRUE@ xwayland-glamor-xv.c -@GLAMOR_EGL_TRUE@am__append_3 = $(glamor_built_sources) -@GLAMOR_EGL_TRUE@am__append_4 = $(GLAMOR_LIBS) $(GBM_LIBS) -lEGL -lGL +@GLAMOR_EGL_TRUE@@XWAYLAND_EGLSTREAM_TRUE@am__append_3 = \ +@GLAMOR_EGL_TRUE@@XWAYLAND_EGLSTREAM_TRUE@ xwayland-glamor-eglstream.c + +@GLAMOR_EGL_TRUE@am__append_4 = $(glamor_built_sources) +@GLAMOR_EGL_TRUE@am__append_5 = $(GLAMOR_LIBS) $(GBM_LIBS) -lEGL -lGL @GLAMOR_EGL_FALSE@Xwayland_DEPENDENCIES = $(glamor_lib) \ -@GLAMOR_EGL_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ +@GLAMOR_EGL_FALSE@ $(am__DEPENDENCIES_1) \ +@GLAMOR_EGL_FALSE@ $(top_builddir)/glx/libglxvnd.la \ +@GLAMOR_EGL_FALSE@ $(am__DEPENDENCIES_1) \ @GLAMOR_EGL_FALSE@ $(top_builddir)/Xext/libXvidmode.la \ @GLAMOR_EGL_FALSE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +@XWAYLAND_EGLSTREAM_TRUE@am__append_6 = \ +@XWAYLAND_EGLSTREAM_TRUE@ wayland-eglstream-client-protocol.h \ +@XWAYLAND_EGLSTREAM_TRUE@ wayland-eglstream-protocol.c \ +@XWAYLAND_EGLSTREAM_TRUE@ wayland-eglstream-controller-client-protocol.h \ +@XWAYLAND_EGLSTREAM_TRUE@ wayland-eglstream-controller-protocol.c + subdir = hw/xwayland DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/depcomp @@ -81,7 +94,7 @@ CONFIG_HEADER = $(top_builddir)/include/do-not-use-config.h \ $(top_builddir)/include/xorg-config.h \ $(top_builddir)/include/xkb-config.h \ $(top_builddir)/include/xwin-config.h \ - $(top_builddir)/include/kdrive-config.h \ + $(top_builddir)/include/xwayland-config.h \ $(top_builddir)/include/version-config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @@ -90,26 +103,36 @@ PROGRAMS = $(bin_PROGRAMS) am__Xwayland_SOURCES_DIST = xwayland.c xwayland-input.c \ xwayland-cursor.c xwayland-shm.c xwayland-output.c \ xwayland-cvt.c xwayland-vidmode.c xwayland.h \ - $(top_srcdir)/Xext/dpmsstubs.c $(top_srcdir)/Xi/stubs.c \ - $(top_srcdir)/mi/miinitext.c xwayland-glamor.c \ - xwayland-glamor-xv.c -@GLAMOR_EGL_TRUE@am__objects_1 = Xwayland-xwayland-glamor.$(OBJEXT) + $(top_srcdir)/Xi/stubs.c $(top_srcdir)/mi/miinitext.c \ + xwayland-glamor.c xwayland-glamor-gbm.c xwayland-present.c \ + xwayland-glamor-xv.c xwayland-glamor-eglstream.c +@GLAMOR_EGL_TRUE@am__objects_1 = Xwayland-xwayland-glamor.$(OBJEXT) \ +@GLAMOR_EGL_TRUE@ Xwayland-xwayland-glamor-gbm.$(OBJEXT) \ +@GLAMOR_EGL_TRUE@ Xwayland-xwayland-present.$(OBJEXT) @GLAMOR_EGL_TRUE@@XV_TRUE@am__objects_2 = Xwayland-xwayland-glamor-xv.$(OBJEXT) +@GLAMOR_EGL_TRUE@@XWAYLAND_EGLSTREAM_TRUE@am__objects_3 = Xwayland-xwayland-glamor-eglstream.$(OBJEXT) am_Xwayland_OBJECTS = Xwayland-xwayland.$(OBJEXT) \ Xwayland-xwayland-input.$(OBJEXT) \ Xwayland-xwayland-cursor.$(OBJEXT) \ Xwayland-xwayland-shm.$(OBJEXT) \ Xwayland-xwayland-output.$(OBJEXT) \ Xwayland-xwayland-cvt.$(OBJEXT) \ - Xwayland-xwayland-vidmode.$(OBJEXT) \ - Xwayland-dpmsstubs.$(OBJEXT) Xwayland-stubs.$(OBJEXT) \ - Xwayland-miinitext.$(OBJEXT) $(am__objects_1) $(am__objects_2) -@GLAMOR_EGL_TRUE@am__objects_3 = Xwayland-drm-protocol.$(OBJEXT) -@GLAMOR_EGL_TRUE@am__objects_4 = $(am__objects_3) -am__objects_5 = $(am__objects_4) \ + Xwayland-xwayland-vidmode.$(OBJEXT) Xwayland-stubs.$(OBJEXT) \ + Xwayland-miinitext.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) +@GLAMOR_EGL_TRUE@am__objects_4 = Xwayland-drm-protocol.$(OBJEXT) +@GLAMOR_EGL_TRUE@am__objects_5 = $(am__objects_4) +@XWAYLAND_EGLSTREAM_TRUE@am__objects_6 = Xwayland-wayland-eglstream-protocol.$(OBJEXT) \ +@XWAYLAND_EGLSTREAM_TRUE@ Xwayland-wayland-eglstream-controller-protocol.$(OBJEXT) +am__objects_7 = $(am__objects_5) \ Xwayland-relative-pointer-unstable-v1-protocol.$(OBJEXT) \ - Xwayland-pointer-constraints-unstable-v1-protocol.$(OBJEXT) -nodist_Xwayland_OBJECTS = $(am__objects_5) + Xwayland-pointer-constraints-unstable-v1-protocol.$(OBJEXT) \ + Xwayland-tablet-unstable-v2-protocol.$(OBJEXT) \ + Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.$(OBJEXT) \ + Xwayland-xdg-output-unstable-v1-protocol.$(OBJEXT) \ + Xwayland-linux-dmabuf-unstable-v1-protocol.$(OBJEXT) \ + $(am__objects_6) +nodist_Xwayland_OBJECTS = $(am__objects_7) Xwayland_OBJECTS = $(am_Xwayland_OBJECTS) $(nodist_Xwayland_OBJECTS) am__DEPENDENCIES_1 = @GLAMOR_EGL_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \ @@ -348,6 +371,7 @@ RANLIB = @RANLIB@ RAWCPP = @RAWCPP@ RAWCPPFLAGS = @RAWCPPFLAGS@ RELEASE_DATE = @RELEASE_DATE@ +SCANNER_ARG = @SCANNER_ARG@ SDK_REQUIRED_MODULES = @SDK_REQUIRED_MODULES@ SED = @SED@ SELINUX_CFLAGS = @SELINUX_CFLAGS@ @@ -366,15 +390,18 @@ SYSCONFDIR = @SYSCONFDIR@ SYSTEMD_DAEMON_CFLAGS = @SYSTEMD_DAEMON_CFLAGS@ SYSTEMD_DAEMON_LIBS = @SYSTEMD_DAEMON_LIBS@ TRADITIONALCPPFLAGS = @TRADITIONALCPPFLAGS@ -TSLIB_CFLAGS = @TSLIB_CFLAGS@ -TSLIB_LIBS = @TSLIB_LIBS@ UDEV_CFLAGS = @UDEV_CFLAGS@ UDEV_LIBS = @UDEV_LIBS@ UTILS_SYS_LIBS = @UTILS_SYS_LIBS@ VENDOR_NAME_SHORT = @VENDOR_NAME_SHORT@ VERSION = @VERSION@ +WAYLAND_EGLSTREAM_CFLAGS = @WAYLAND_EGLSTREAM_CFLAGS@ +WAYLAND_EGLSTREAM_DATADIR = @WAYLAND_EGLSTREAM_DATADIR@ +WAYLAND_EGLSTREAM_LIBS = @WAYLAND_EGLSTREAM_LIBS@ WAYLAND_PROTOCOLS_DATADIR = @WAYLAND_PROTOCOLS_DATADIR@ WAYLAND_SCANNER = @WAYLAND_SCANNER@ +WAYLAND_SCANNER_CFLAGS = @WAYLAND_SCANNER_CFLAGS@ +WAYLAND_SCANNER_LIBS = @WAYLAND_SCANNER_LIBS@ WINDOWSDRI_CFLAGS = @WINDOWSDRI_CFLAGS@ WINDOWSDRI_LIBS = @WINDOWSDRI_LIBS@ WINDOWSWM_CFLAGS = @WINDOWSWM_CFLAGS@ @@ -382,6 +409,8 @@ WINDOWSWM_LIBS = @WINDOWSWM_LIBS@ WINDRES = @WINDRES@ X11EXAMPLES_DEP_CFLAGS = @X11EXAMPLES_DEP_CFLAGS@ X11EXAMPLES_DEP_LIBS = @X11EXAMPLES_DEP_LIBS@ +XCONFIGDIR = @XCONFIGDIR@ +XCONFIGFILE = @XCONFIGFILE@ XDMCP_CFLAGS = @XDMCP_CFLAGS@ XDMCP_LIBS = @XDMCP_LIBS@ XDMXCONFIG_DEP_CFLAGS = @XDMXCONFIG_DEP_CFLAGS@ @@ -453,8 +482,6 @@ XWIN_SERVER_NAME = @XWIN_SERVER_NAME@ XWIN_SYS_LIBS = @XWIN_SYS_LIBS@ YACC = @YACC@ YFLAGS = @YFLAGS@ -__XCONFIGDIR__ = @__XCONFIGDIR__@ -__XCONFIGFILE__ = @__XCONFIGFILE__@ abi_ansic = @abi_ansic@ abi_extension = @abi_extension@ abi_videodrv = @abi_videodrv@ @@ -530,18 +557,27 @@ Xwayland_CFLAGS = \ Xwayland_SOURCES = xwayland.c xwayland-input.c xwayland-cursor.c \ xwayland-shm.c xwayland-output.c xwayland-cvt.c \ - xwayland-vidmode.c xwayland.h $(top_srcdir)/Xext/dpmsstubs.c \ - $(top_srcdir)/Xi/stubs.c $(top_srcdir)/mi/miinitext.c \ - $(am__append_1) $(am__append_2) -Xwayland_LDADD = $(glamor_lib) $(XWAYLAND_LIBS) $(XWAYLAND_SYS_LIBS) \ + xwayland-vidmode.c xwayland.h $(top_srcdir)/Xi/stubs.c \ + $(top_srcdir)/mi/miinitext.c $(am__append_1) $(am__append_2) \ + $(am__append_3) +Xwayland_LDADD = $(glamor_lib) $(XWAYLAND_LIBS) \ + $(top_builddir)/glx/libglxvnd.la $(XWAYLAND_SYS_LIBS) \ $(top_builddir)/Xext/libXvidmode.la $(XSERVER_SYS_LIBS) \ - $(am__append_4) + $(am__append_5) Xwayland_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG) -Xwayland_built_sources = $(am__append_3) \ +Xwayland_built_sources = $(am__append_4) \ relative-pointer-unstable-v1-client-protocol.h \ relative-pointer-unstable-v1-protocol.c \ pointer-constraints-unstable-v1-client-protocol.h \ - pointer-constraints-unstable-v1-protocol.c + pointer-constraints-unstable-v1-protocol.c \ + tablet-unstable-v2-client-protocol.h \ + tablet-unstable-v2-protocol.c \ + xwayland-keyboard-grab-unstable-v1-protocol.c \ + xwayland-keyboard-grab-unstable-v1-client-protocol.h \ + xdg-output-unstable-v1-protocol.c \ + xdg-output-unstable-v1-client-protocol.h \ + linux-dmabuf-unstable-v1-client-protocol.h \ + linux-dmabuf-unstable-v1-protocol.c $(am__append_6) @GLAMOR_EGL_TRUE@glamor_built_sources = \ @GLAMOR_EGL_TRUE@ drm-client-protocol.h \ @GLAMOR_EGL_TRUE@ drm-protocol.c @@ -641,18 +677,26 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-dpmsstubs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-drm-protocol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-linux-dmabuf-unstable-v1-protocol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-miinitext.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-pointer-constraints-unstable-v1-protocol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-relative-pointer-unstable-v1-protocol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-stubs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-tablet-unstable-v2-protocol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-wayland-eglstream-controller-protocol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-wayland-eglstream-protocol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xdg-output-unstable-v1-protocol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland-cursor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland-cvt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland-glamor-eglstream.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland-glamor-gbm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland-glamor-xv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland-glamor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland-input.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland-output.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland-present.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland-shm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland-vidmode.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xwayland-xwayland.Po@am__quote@ @@ -776,20 +820,6 @@ Xwayland-xwayland-vidmode.obj: xwayland-vidmode.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xwayland-vidmode.obj `if test -f 'xwayland-vidmode.c'; then $(CYGPATH_W) 'xwayland-vidmode.c'; else $(CYGPATH_W) '$(srcdir)/xwayland-vidmode.c'; fi` -Xwayland-dpmsstubs.o: $(top_srcdir)/Xext/dpmsstubs.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-dpmsstubs.o -MD -MP -MF $(DEPDIR)/Xwayland-dpmsstubs.Tpo -c -o Xwayland-dpmsstubs.o `test -f '$(top_srcdir)/Xext/dpmsstubs.c' || echo '$(srcdir)/'`$(top_srcdir)/Xext/dpmsstubs.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-dpmsstubs.Tpo $(DEPDIR)/Xwayland-dpmsstubs.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/Xext/dpmsstubs.c' object='Xwayland-dpmsstubs.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-dpmsstubs.o `test -f '$(top_srcdir)/Xext/dpmsstubs.c' || echo '$(srcdir)/'`$(top_srcdir)/Xext/dpmsstubs.c - -Xwayland-dpmsstubs.obj: $(top_srcdir)/Xext/dpmsstubs.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-dpmsstubs.obj -MD -MP -MF $(DEPDIR)/Xwayland-dpmsstubs.Tpo -c -o Xwayland-dpmsstubs.obj `if test -f '$(top_srcdir)/Xext/dpmsstubs.c'; then $(CYGPATH_W) '$(top_srcdir)/Xext/dpmsstubs.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/Xext/dpmsstubs.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-dpmsstubs.Tpo $(DEPDIR)/Xwayland-dpmsstubs.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/Xext/dpmsstubs.c' object='Xwayland-dpmsstubs.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-dpmsstubs.obj `if test -f '$(top_srcdir)/Xext/dpmsstubs.c'; then $(CYGPATH_W) '$(top_srcdir)/Xext/dpmsstubs.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/Xext/dpmsstubs.c'; fi` - Xwayland-stubs.o: $(top_srcdir)/Xi/stubs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-stubs.o -MD -MP -MF $(DEPDIR)/Xwayland-stubs.Tpo -c -o Xwayland-stubs.o `test -f '$(top_srcdir)/Xi/stubs.c' || echo '$(srcdir)/'`$(top_srcdir)/Xi/stubs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-stubs.Tpo $(DEPDIR)/Xwayland-stubs.Po @@ -832,6 +862,34 @@ Xwayland-xwayland-glamor.obj: xwayland-glamor.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xwayland-glamor.obj `if test -f 'xwayland-glamor.c'; then $(CYGPATH_W) 'xwayland-glamor.c'; else $(CYGPATH_W) '$(srcdir)/xwayland-glamor.c'; fi` +Xwayland-xwayland-glamor-gbm.o: xwayland-glamor-gbm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-xwayland-glamor-gbm.o -MD -MP -MF $(DEPDIR)/Xwayland-xwayland-glamor-gbm.Tpo -c -o Xwayland-xwayland-glamor-gbm.o `test -f 'xwayland-glamor-gbm.c' || echo '$(srcdir)/'`xwayland-glamor-gbm.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-xwayland-glamor-gbm.Tpo $(DEPDIR)/Xwayland-xwayland-glamor-gbm.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xwayland-glamor-gbm.c' object='Xwayland-xwayland-glamor-gbm.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xwayland-glamor-gbm.o `test -f 'xwayland-glamor-gbm.c' || echo '$(srcdir)/'`xwayland-glamor-gbm.c + +Xwayland-xwayland-glamor-gbm.obj: xwayland-glamor-gbm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-xwayland-glamor-gbm.obj -MD -MP -MF $(DEPDIR)/Xwayland-xwayland-glamor-gbm.Tpo -c -o Xwayland-xwayland-glamor-gbm.obj `if test -f 'xwayland-glamor-gbm.c'; then $(CYGPATH_W) 'xwayland-glamor-gbm.c'; else $(CYGPATH_W) '$(srcdir)/xwayland-glamor-gbm.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-xwayland-glamor-gbm.Tpo $(DEPDIR)/Xwayland-xwayland-glamor-gbm.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xwayland-glamor-gbm.c' object='Xwayland-xwayland-glamor-gbm.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xwayland-glamor-gbm.obj `if test -f 'xwayland-glamor-gbm.c'; then $(CYGPATH_W) 'xwayland-glamor-gbm.c'; else $(CYGPATH_W) '$(srcdir)/xwayland-glamor-gbm.c'; fi` + +Xwayland-xwayland-present.o: xwayland-present.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-xwayland-present.o -MD -MP -MF $(DEPDIR)/Xwayland-xwayland-present.Tpo -c -o Xwayland-xwayland-present.o `test -f 'xwayland-present.c' || echo '$(srcdir)/'`xwayland-present.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-xwayland-present.Tpo $(DEPDIR)/Xwayland-xwayland-present.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xwayland-present.c' object='Xwayland-xwayland-present.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xwayland-present.o `test -f 'xwayland-present.c' || echo '$(srcdir)/'`xwayland-present.c + +Xwayland-xwayland-present.obj: xwayland-present.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-xwayland-present.obj -MD -MP -MF $(DEPDIR)/Xwayland-xwayland-present.Tpo -c -o Xwayland-xwayland-present.obj `if test -f 'xwayland-present.c'; then $(CYGPATH_W) 'xwayland-present.c'; else $(CYGPATH_W) '$(srcdir)/xwayland-present.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-xwayland-present.Tpo $(DEPDIR)/Xwayland-xwayland-present.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xwayland-present.c' object='Xwayland-xwayland-present.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xwayland-present.obj `if test -f 'xwayland-present.c'; then $(CYGPATH_W) 'xwayland-present.c'; else $(CYGPATH_W) '$(srcdir)/xwayland-present.c'; fi` + Xwayland-xwayland-glamor-xv.o: xwayland-glamor-xv.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-xwayland-glamor-xv.o -MD -MP -MF $(DEPDIR)/Xwayland-xwayland-glamor-xv.Tpo -c -o Xwayland-xwayland-glamor-xv.o `test -f 'xwayland-glamor-xv.c' || echo '$(srcdir)/'`xwayland-glamor-xv.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-xwayland-glamor-xv.Tpo $(DEPDIR)/Xwayland-xwayland-glamor-xv.Po @@ -846,6 +904,20 @@ Xwayland-xwayland-glamor-xv.obj: xwayland-glamor-xv.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xwayland-glamor-xv.obj `if test -f 'xwayland-glamor-xv.c'; then $(CYGPATH_W) 'xwayland-glamor-xv.c'; else $(CYGPATH_W) '$(srcdir)/xwayland-glamor-xv.c'; fi` +Xwayland-xwayland-glamor-eglstream.o: xwayland-glamor-eglstream.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-xwayland-glamor-eglstream.o -MD -MP -MF $(DEPDIR)/Xwayland-xwayland-glamor-eglstream.Tpo -c -o Xwayland-xwayland-glamor-eglstream.o `test -f 'xwayland-glamor-eglstream.c' || echo '$(srcdir)/'`xwayland-glamor-eglstream.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-xwayland-glamor-eglstream.Tpo $(DEPDIR)/Xwayland-xwayland-glamor-eglstream.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xwayland-glamor-eglstream.c' object='Xwayland-xwayland-glamor-eglstream.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xwayland-glamor-eglstream.o `test -f 'xwayland-glamor-eglstream.c' || echo '$(srcdir)/'`xwayland-glamor-eglstream.c + +Xwayland-xwayland-glamor-eglstream.obj: xwayland-glamor-eglstream.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-xwayland-glamor-eglstream.obj -MD -MP -MF $(DEPDIR)/Xwayland-xwayland-glamor-eglstream.Tpo -c -o Xwayland-xwayland-glamor-eglstream.obj `if test -f 'xwayland-glamor-eglstream.c'; then $(CYGPATH_W) 'xwayland-glamor-eglstream.c'; else $(CYGPATH_W) '$(srcdir)/xwayland-glamor-eglstream.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-xwayland-glamor-eglstream.Tpo $(DEPDIR)/Xwayland-xwayland-glamor-eglstream.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xwayland-glamor-eglstream.c' object='Xwayland-xwayland-glamor-eglstream.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xwayland-glamor-eglstream.obj `if test -f 'xwayland-glamor-eglstream.c'; then $(CYGPATH_W) 'xwayland-glamor-eglstream.c'; else $(CYGPATH_W) '$(srcdir)/xwayland-glamor-eglstream.c'; fi` + Xwayland-drm-protocol.o: drm-protocol.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-drm-protocol.o -MD -MP -MF $(DEPDIR)/Xwayland-drm-protocol.Tpo -c -o Xwayland-drm-protocol.o `test -f 'drm-protocol.c' || echo '$(srcdir)/'`drm-protocol.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-drm-protocol.Tpo $(DEPDIR)/Xwayland-drm-protocol.Po @@ -888,6 +960,90 @@ Xwayland-pointer-constraints-unstable-v1-protocol.obj: pointer-constraints-unsta @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-pointer-constraints-unstable-v1-protocol.obj `if test -f 'pointer-constraints-unstable-v1-protocol.c'; then $(CYGPATH_W) 'pointer-constraints-unstable-v1-protocol.c'; else $(CYGPATH_W) '$(srcdir)/pointer-constraints-unstable-v1-protocol.c'; fi` +Xwayland-tablet-unstable-v2-protocol.o: tablet-unstable-v2-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-tablet-unstable-v2-protocol.o -MD -MP -MF $(DEPDIR)/Xwayland-tablet-unstable-v2-protocol.Tpo -c -o Xwayland-tablet-unstable-v2-protocol.o `test -f 'tablet-unstable-v2-protocol.c' || echo '$(srcdir)/'`tablet-unstable-v2-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-tablet-unstable-v2-protocol.Tpo $(DEPDIR)/Xwayland-tablet-unstable-v2-protocol.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tablet-unstable-v2-protocol.c' object='Xwayland-tablet-unstable-v2-protocol.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-tablet-unstable-v2-protocol.o `test -f 'tablet-unstable-v2-protocol.c' || echo '$(srcdir)/'`tablet-unstable-v2-protocol.c + +Xwayland-tablet-unstable-v2-protocol.obj: tablet-unstable-v2-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-tablet-unstable-v2-protocol.obj -MD -MP -MF $(DEPDIR)/Xwayland-tablet-unstable-v2-protocol.Tpo -c -o Xwayland-tablet-unstable-v2-protocol.obj `if test -f 'tablet-unstable-v2-protocol.c'; then $(CYGPATH_W) 'tablet-unstable-v2-protocol.c'; else $(CYGPATH_W) '$(srcdir)/tablet-unstable-v2-protocol.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-tablet-unstable-v2-protocol.Tpo $(DEPDIR)/Xwayland-tablet-unstable-v2-protocol.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tablet-unstable-v2-protocol.c' object='Xwayland-tablet-unstable-v2-protocol.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-tablet-unstable-v2-protocol.obj `if test -f 'tablet-unstable-v2-protocol.c'; then $(CYGPATH_W) 'tablet-unstable-v2-protocol.c'; else $(CYGPATH_W) '$(srcdir)/tablet-unstable-v2-protocol.c'; fi` + +Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.o: xwayland-keyboard-grab-unstable-v1-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.o -MD -MP -MF $(DEPDIR)/Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.Tpo -c -o Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.o `test -f 'xwayland-keyboard-grab-unstable-v1-protocol.c' || echo '$(srcdir)/'`xwayland-keyboard-grab-unstable-v1-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.Tpo $(DEPDIR)/Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xwayland-keyboard-grab-unstable-v1-protocol.c' object='Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.o `test -f 'xwayland-keyboard-grab-unstable-v1-protocol.c' || echo '$(srcdir)/'`xwayland-keyboard-grab-unstable-v1-protocol.c + +Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.obj: xwayland-keyboard-grab-unstable-v1-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.obj -MD -MP -MF $(DEPDIR)/Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.Tpo -c -o Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.obj `if test -f 'xwayland-keyboard-grab-unstable-v1-protocol.c'; then $(CYGPATH_W) 'xwayland-keyboard-grab-unstable-v1-protocol.c'; else $(CYGPATH_W) '$(srcdir)/xwayland-keyboard-grab-unstable-v1-protocol.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.Tpo $(DEPDIR)/Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xwayland-keyboard-grab-unstable-v1-protocol.c' object='Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xwayland-keyboard-grab-unstable-v1-protocol.obj `if test -f 'xwayland-keyboard-grab-unstable-v1-protocol.c'; then $(CYGPATH_W) 'xwayland-keyboard-grab-unstable-v1-protocol.c'; else $(CYGPATH_W) '$(srcdir)/xwayland-keyboard-grab-unstable-v1-protocol.c'; fi` + +Xwayland-xdg-output-unstable-v1-protocol.o: xdg-output-unstable-v1-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-xdg-output-unstable-v1-protocol.o -MD -MP -MF $(DEPDIR)/Xwayland-xdg-output-unstable-v1-protocol.Tpo -c -o Xwayland-xdg-output-unstable-v1-protocol.o `test -f 'xdg-output-unstable-v1-protocol.c' || echo '$(srcdir)/'`xdg-output-unstable-v1-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-xdg-output-unstable-v1-protocol.Tpo $(DEPDIR)/Xwayland-xdg-output-unstable-v1-protocol.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xdg-output-unstable-v1-protocol.c' object='Xwayland-xdg-output-unstable-v1-protocol.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xdg-output-unstable-v1-protocol.o `test -f 'xdg-output-unstable-v1-protocol.c' || echo '$(srcdir)/'`xdg-output-unstable-v1-protocol.c + +Xwayland-xdg-output-unstable-v1-protocol.obj: xdg-output-unstable-v1-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-xdg-output-unstable-v1-protocol.obj -MD -MP -MF $(DEPDIR)/Xwayland-xdg-output-unstable-v1-protocol.Tpo -c -o Xwayland-xdg-output-unstable-v1-protocol.obj `if test -f 'xdg-output-unstable-v1-protocol.c'; then $(CYGPATH_W) 'xdg-output-unstable-v1-protocol.c'; else $(CYGPATH_W) '$(srcdir)/xdg-output-unstable-v1-protocol.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-xdg-output-unstable-v1-protocol.Tpo $(DEPDIR)/Xwayland-xdg-output-unstable-v1-protocol.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xdg-output-unstable-v1-protocol.c' object='Xwayland-xdg-output-unstable-v1-protocol.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-xdg-output-unstable-v1-protocol.obj `if test -f 'xdg-output-unstable-v1-protocol.c'; then $(CYGPATH_W) 'xdg-output-unstable-v1-protocol.c'; else $(CYGPATH_W) '$(srcdir)/xdg-output-unstable-v1-protocol.c'; fi` + +Xwayland-linux-dmabuf-unstable-v1-protocol.o: linux-dmabuf-unstable-v1-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-linux-dmabuf-unstable-v1-protocol.o -MD -MP -MF $(DEPDIR)/Xwayland-linux-dmabuf-unstable-v1-protocol.Tpo -c -o Xwayland-linux-dmabuf-unstable-v1-protocol.o `test -f 'linux-dmabuf-unstable-v1-protocol.c' || echo '$(srcdir)/'`linux-dmabuf-unstable-v1-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-linux-dmabuf-unstable-v1-protocol.Tpo $(DEPDIR)/Xwayland-linux-dmabuf-unstable-v1-protocol.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='linux-dmabuf-unstable-v1-protocol.c' object='Xwayland-linux-dmabuf-unstable-v1-protocol.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-linux-dmabuf-unstable-v1-protocol.o `test -f 'linux-dmabuf-unstable-v1-protocol.c' || echo '$(srcdir)/'`linux-dmabuf-unstable-v1-protocol.c + +Xwayland-linux-dmabuf-unstable-v1-protocol.obj: linux-dmabuf-unstable-v1-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-linux-dmabuf-unstable-v1-protocol.obj -MD -MP -MF $(DEPDIR)/Xwayland-linux-dmabuf-unstable-v1-protocol.Tpo -c -o Xwayland-linux-dmabuf-unstable-v1-protocol.obj `if test -f 'linux-dmabuf-unstable-v1-protocol.c'; then $(CYGPATH_W) 'linux-dmabuf-unstable-v1-protocol.c'; else $(CYGPATH_W) '$(srcdir)/linux-dmabuf-unstable-v1-protocol.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-linux-dmabuf-unstable-v1-protocol.Tpo $(DEPDIR)/Xwayland-linux-dmabuf-unstable-v1-protocol.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='linux-dmabuf-unstable-v1-protocol.c' object='Xwayland-linux-dmabuf-unstable-v1-protocol.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-linux-dmabuf-unstable-v1-protocol.obj `if test -f 'linux-dmabuf-unstable-v1-protocol.c'; then $(CYGPATH_W) 'linux-dmabuf-unstable-v1-protocol.c'; else $(CYGPATH_W) '$(srcdir)/linux-dmabuf-unstable-v1-protocol.c'; fi` + +Xwayland-wayland-eglstream-protocol.o: wayland-eglstream-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-wayland-eglstream-protocol.o -MD -MP -MF $(DEPDIR)/Xwayland-wayland-eglstream-protocol.Tpo -c -o Xwayland-wayland-eglstream-protocol.o `test -f 'wayland-eglstream-protocol.c' || echo '$(srcdir)/'`wayland-eglstream-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-wayland-eglstream-protocol.Tpo $(DEPDIR)/Xwayland-wayland-eglstream-protocol.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wayland-eglstream-protocol.c' object='Xwayland-wayland-eglstream-protocol.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-wayland-eglstream-protocol.o `test -f 'wayland-eglstream-protocol.c' || echo '$(srcdir)/'`wayland-eglstream-protocol.c + +Xwayland-wayland-eglstream-protocol.obj: wayland-eglstream-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-wayland-eglstream-protocol.obj -MD -MP -MF $(DEPDIR)/Xwayland-wayland-eglstream-protocol.Tpo -c -o Xwayland-wayland-eglstream-protocol.obj `if test -f 'wayland-eglstream-protocol.c'; then $(CYGPATH_W) 'wayland-eglstream-protocol.c'; else $(CYGPATH_W) '$(srcdir)/wayland-eglstream-protocol.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-wayland-eglstream-protocol.Tpo $(DEPDIR)/Xwayland-wayland-eglstream-protocol.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wayland-eglstream-protocol.c' object='Xwayland-wayland-eglstream-protocol.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-wayland-eglstream-protocol.obj `if test -f 'wayland-eglstream-protocol.c'; then $(CYGPATH_W) 'wayland-eglstream-protocol.c'; else $(CYGPATH_W) '$(srcdir)/wayland-eglstream-protocol.c'; fi` + +Xwayland-wayland-eglstream-controller-protocol.o: wayland-eglstream-controller-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-wayland-eglstream-controller-protocol.o -MD -MP -MF $(DEPDIR)/Xwayland-wayland-eglstream-controller-protocol.Tpo -c -o Xwayland-wayland-eglstream-controller-protocol.o `test -f 'wayland-eglstream-controller-protocol.c' || echo '$(srcdir)/'`wayland-eglstream-controller-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-wayland-eglstream-controller-protocol.Tpo $(DEPDIR)/Xwayland-wayland-eglstream-controller-protocol.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wayland-eglstream-controller-protocol.c' object='Xwayland-wayland-eglstream-controller-protocol.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-wayland-eglstream-controller-protocol.o `test -f 'wayland-eglstream-controller-protocol.c' || echo '$(srcdir)/'`wayland-eglstream-controller-protocol.c + +Xwayland-wayland-eglstream-controller-protocol.obj: wayland-eglstream-controller-protocol.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -MT Xwayland-wayland-eglstream-controller-protocol.obj -MD -MP -MF $(DEPDIR)/Xwayland-wayland-eglstream-controller-protocol.Tpo -c -o Xwayland-wayland-eglstream-controller-protocol.obj `if test -f 'wayland-eglstream-controller-protocol.c'; then $(CYGPATH_W) 'wayland-eglstream-controller-protocol.c'; else $(CYGPATH_W) '$(srcdir)/wayland-eglstream-controller-protocol.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/Xwayland-wayland-eglstream-controller-protocol.Tpo $(DEPDIR)/Xwayland-wayland-eglstream-controller-protocol.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wayland-eglstream-controller-protocol.c' object='Xwayland-wayland-eglstream-controller-protocol.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(Xwayland_CFLAGS) $(CFLAGS) -c -o Xwayland-wayland-eglstream-controller-protocol.obj `if test -f 'wayland-eglstream-controller-protocol.c'; then $(CYGPATH_W) 'wayland-eglstream-controller-protocol.c'; else $(CYGPATH_W) '$(srcdir)/wayland-eglstream-controller-protocol.c'; fi` + mostlyclean-libtool: -rm -f *.lo @@ -1121,17 +1277,46 @@ relink: $(AM_V_at)rm -f Xwayland$(EXEEXT) && $(MAKE) Xwayland$(EXEEXT) relative-pointer-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/relative-pointer/relative-pointer-unstable-v1.xml - $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ relative-pointer-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/relative-pointer/relative-pointer-unstable-v1.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ pointer-constraints-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml - $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ pointer-constraints-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ -%-protocol.c : %.xml +tablet-unstable-v2-protocol.c: $(WAYLAND_PROTOCOLS_DATADIR)/unstable/tablet/tablet-unstable-v2.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ +tablet-unstable-v2-client-protocol.h: $(WAYLAND_PROTOCOLS_DATADIR)/unstable/tablet/tablet-unstable-v2.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ + +xwayland-keyboard-grab-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xwayland-keyboard-grab/xwayland-keyboard-grab-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ +xwayland-keyboard-grab-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xwayland-keyboard-grab/xwayland-keyboard-grab-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ +xdg-output-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xdg-output/xdg-output-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ +xdg-output-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/xdg-output/xdg-output-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ + +linux-dmabuf-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ +linux-dmabuf-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ + +wayland-eglstream-client-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ +wayland-eglstream-controller-client-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream-controller.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ + +wayland-eglstream-protocol.c : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream.xml $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ +wayland-eglstream-controller-protocol.c : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream-controller.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) code < $< > $@ + +%-protocol.c : %.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ %-client-protocol.h : %.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ diff --git a/xserver/hw/xwayland/xwayland-cursor.c b/xserver/hw/xwayland/xwayland-cursor.c index 7b6a698fd..cf8395f1d 100644 --- a/xserver/hw/xwayland/xwayland-cursor.c +++ b/xserver/hw/xwayland/xwayland-cursor.c @@ -96,11 +96,11 @@ xwl_unrealize_cursor(DeviceIntPtr device, ScreenPtr screen, CursorPtr cursor) } static void -clear_cursor_frame_callback(struct xwl_seat *xwl_seat) +clear_cursor_frame_callback(struct xwl_cursor *xwl_cursor) { - if (xwl_seat->cursor_frame_cb) { - wl_callback_destroy (xwl_seat->cursor_frame_cb); - xwl_seat->cursor_frame_cb = NULL; + if (xwl_cursor->frame_cb) { + wl_callback_destroy (xwl_cursor->frame_cb); + xwl_cursor->frame_cb = NULL; } } @@ -109,12 +109,12 @@ frame_callback(void *data, struct wl_callback *callback, uint32_t time) { - struct xwl_seat *xwl_seat = data; + struct xwl_cursor *xwl_cursor = data; - clear_cursor_frame_callback(xwl_seat); - if (xwl_seat->cursor_needs_update) { - xwl_seat->cursor_needs_update = FALSE; - xwl_seat_set_cursor(xwl_seat); + clear_cursor_frame_callback(xwl_cursor); + if (xwl_cursor->needs_update) { + xwl_cursor->needs_update = FALSE; + xwl_cursor->update_proc(xwl_cursor); } } @@ -125,6 +125,7 @@ static const struct wl_callback_listener frame_listener = { void xwl_seat_set_cursor(struct xwl_seat *xwl_seat) { + struct xwl_cursor *xwl_cursor = &xwl_seat->cursor; PixmapPtr pixmap; CursorPtr cursor; int stride; @@ -135,13 +136,13 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat) if (!xwl_seat->x_cursor) { wl_pointer_set_cursor(xwl_seat->wl_pointer, xwl_seat->pointer_enter_serial, NULL, 0, 0); - clear_cursor_frame_callback(xwl_seat); - xwl_seat->cursor_needs_update = FALSE; + clear_cursor_frame_callback(xwl_cursor); + xwl_cursor->needs_update = FALSE; return; } - if (xwl_seat->cursor_frame_cb) { - xwl_seat->cursor_needs_update = TRUE; + if (xwl_cursor->frame_cb) { + xwl_cursor->needs_update = TRUE; return; } @@ -159,19 +160,69 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat) wl_pointer_set_cursor(xwl_seat->wl_pointer, xwl_seat->pointer_enter_serial, - xwl_seat->cursor, + xwl_cursor->surface, xwl_seat->x_cursor->bits->xhot, xwl_seat->x_cursor->bits->yhot); - wl_surface_attach(xwl_seat->cursor, + wl_surface_attach(xwl_cursor->surface, xwl_shm_pixmap_get_wl_buffer(pixmap), 0, 0); - wl_surface_damage(xwl_seat->cursor, 0, 0, + wl_surface_damage(xwl_cursor->surface, 0, 0, xwl_seat->x_cursor->bits->width, xwl_seat->x_cursor->bits->height); - xwl_seat->cursor_frame_cb = wl_surface_frame(xwl_seat->cursor); - wl_callback_add_listener(xwl_seat->cursor_frame_cb, &frame_listener, xwl_seat); + xwl_cursor->frame_cb = wl_surface_frame(xwl_cursor->surface); + wl_callback_add_listener(xwl_cursor->frame_cb, &frame_listener, xwl_cursor); - wl_surface_commit(xwl_seat->cursor); + wl_surface_commit(xwl_cursor->surface); +} + +void +xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool) +{ + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor; + PixmapPtr pixmap; + CursorPtr cursor; + int stride; + + if (!xwl_seat->x_cursor) { + zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool, + xwl_tablet_tool->proximity_in_serial, + NULL, 0, 0); + return; + } + + if (xwl_cursor->frame_cb) { + xwl_cursor->needs_update = TRUE; + return; + } + + cursor = xwl_seat->x_cursor; + pixmap = dixGetPrivate(&cursor->devPrivates, &xwl_cursor_private_key); + if (!pixmap) + return; + + stride = cursor->bits->width * 4; + if (cursor->bits->argb) + memcpy(pixmap->devPrivate.ptr, + cursor->bits->argb, cursor->bits->height * stride); + else + expand_source_and_mask(cursor, pixmap->devPrivate.ptr); + + zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool, + xwl_tablet_tool->proximity_in_serial, + xwl_cursor->surface, + xwl_seat->x_cursor->bits->xhot, + xwl_seat->x_cursor->bits->yhot); + wl_surface_attach(xwl_cursor->surface, + xwl_shm_pixmap_get_wl_buffer(pixmap), 0, 0); + wl_surface_damage(xwl_cursor->surface, 0, 0, + xwl_seat->x_cursor->bits->width, + xwl_seat->x_cursor->bits->height); + + xwl_cursor->frame_cb = wl_surface_frame(xwl_cursor->surface); + wl_callback_add_listener(xwl_cursor->frame_cb, &frame_listener, xwl_cursor); + + wl_surface_commit(xwl_cursor->surface); } static void @@ -179,6 +230,7 @@ xwl_set_cursor(DeviceIntPtr device, ScreenPtr screen, CursorPtr cursor, int x, int y) { struct xwl_seat *xwl_seat; + struct xwl_tablet_tool *xwl_tablet_tool; Bool cursor_visibility_changed; xwl_seat = device->public.devicePrivate; @@ -193,6 +245,11 @@ xwl_set_cursor(DeviceIntPtr device, xwl_seat_cursor_visibility_changed(xwl_seat); xwl_seat_set_cursor(xwl_seat); + + xorg_list_for_each_entry(xwl_tablet_tool, &xwl_seat->tablet_tools, link) { + if (xwl_tablet_tool->proximity_in_serial != 0) + xwl_tablet_tool_set_cursor(xwl_tablet_tool); + } } static void diff --git a/xserver/hw/xwayland/xwayland-glamor-eglstream.c b/xserver/hw/xwayland/xwayland-glamor-eglstream.c new file mode 100644 index 000000000..c62c0d2ac --- /dev/null +++ b/xserver/hw/xwayland/xwayland-glamor-eglstream.c @@ -0,0 +1,932 @@ +/* + * Copyright © 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including + * the next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Lyude Paul <lyude@redhat.com> + * + */ + +#include "xwayland.h" + +#include "wayland-eglstream-client-protocol.h" +#include "wayland-eglstream-controller-client-protocol.h" + +#define MESA_EGL_NO_X11_HEADERS +#include <glamor_egl.h> +#include <glamor.h> +#include <glamor_transform.h> +#include <glamor_transfer.h> + +#include <xf86drm.h> + +#include <epoxy/egl.h> + +struct xwl_eglstream_pending_stream { + PixmapPtr pixmap; + WindowPtr window; + + struct xwl_pixmap *xwl_pixmap; + struct wl_callback *cb; + + Bool is_valid; + + struct xorg_list link; +}; + +struct xwl_eglstream_private { + EGLDeviceEXT egl_device; + struct wl_eglstream_display *display; + struct wl_eglstream_controller *controller; + uint32_t display_caps; + + EGLConfig config; + + SetWindowPixmapProcPtr SetWindowPixmap; + + struct xorg_list pending_streams; + + Bool have_egl_damage; + + GLint blit_prog; + GLuint blit_vao; + GLuint blit_vbo; + GLuint blit_is_rgba_pos; +}; + +struct xwl_pixmap { + struct wl_buffer *buffer; + struct xwl_screen *xwl_screen; + + /* The stream and associated resources have their own lifetime seperate + * from the pixmap's */ + int refcount; + + EGLStreamKHR stream; + EGLSurface surface; +}; + +static DevPrivateKeyRec xwl_eglstream_private_key; +static DevPrivateKeyRec xwl_eglstream_window_private_key; + +static inline struct xwl_eglstream_private * +xwl_eglstream_get(struct xwl_screen *xwl_screen) +{ + return dixLookupPrivate(&xwl_screen->screen->devPrivates, + &xwl_eglstream_private_key); +} + +static inline struct xwl_eglstream_pending_stream * +xwl_eglstream_window_get_pending(WindowPtr window) +{ + return dixLookupPrivate(&window->devPrivates, + &xwl_eglstream_window_private_key); +} + +static inline void +xwl_eglstream_window_set_pending(WindowPtr window, + struct xwl_eglstream_pending_stream *stream) +{ + dixSetPrivate(&window->devPrivates, + &xwl_eglstream_window_private_key, stream); +} + +static GLint +xwl_eglstream_compile_glsl_prog(GLenum type, const char *source) +{ + GLint ok; + GLint prog; + + prog = glCreateShader(type); + glShaderSource(prog, 1, (const GLchar **) &source, NULL); + glCompileShader(prog); + glGetShaderiv(prog, GL_COMPILE_STATUS, &ok); + if (!ok) { + GLchar *info; + GLint size; + + glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &size); + info = malloc(size); + if (info) { + glGetShaderInfoLog(prog, size, NULL, info); + ErrorF("Failed to compile %s: %s\n", + type == GL_FRAGMENT_SHADER ? "FS" : "VS", info); + ErrorF("Program source:\n%s", source); + free(info); + } + else + ErrorF("Failed to get shader compilation info.\n"); + FatalError("GLSL compile failure\n"); + } + + return prog; +} + +static GLuint +xwl_eglstream_build_glsl_prog(GLuint vs, GLuint fs) +{ + GLint ok; + GLuint prog; + + prog = glCreateProgram(); + glAttachShader(prog, vs); + glAttachShader(prog, fs); + + glLinkProgram(prog); + glGetProgramiv(prog, GL_LINK_STATUS, &ok); + if (!ok) { + GLchar *info; + GLint size; + + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size); + info = malloc(size); + + glGetProgramInfoLog(prog, size, NULL, info); + ErrorF("Failed to link: %s\n", info); + FatalError("GLSL link failure\n"); + } + + return prog; +} + +static void +xwl_eglstream_cleanup(struct xwl_screen *xwl_screen) +{ + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); + + if (xwl_eglstream->display) + wl_eglstream_display_destroy(xwl_eglstream->display); + if (xwl_eglstream->controller) + wl_eglstream_controller_destroy(xwl_eglstream->controller); + if (xwl_eglstream->blit_prog) { + glDeleteProgram(xwl_eglstream->blit_prog); + glDeleteBuffers(1, &xwl_eglstream->blit_vbo); + } + + free(xwl_eglstream); +} + +static Bool +xwl_glamor_egl_supports_device_probing(void) +{ + return epoxy_has_egl_extension(NULL, "EGL_EXT_device_base"); +} + +static void ** +xwl_glamor_egl_get_devices(int *num_devices) +{ + EGLDeviceEXT *devices, *tmp; + Bool ret; + int drm_dev_count = 0; + int i; + + if (!xwl_glamor_egl_supports_device_probing()) + return NULL; + + /* Get the number of devices */ + ret = eglQueryDevicesEXT(0, NULL, num_devices); + if (!ret || *num_devices < 1) + return NULL; + + devices = calloc(*num_devices, sizeof(EGLDeviceEXT)); + if (!devices) + return NULL; + + ret = eglQueryDevicesEXT(*num_devices, devices, num_devices); + if (!ret) + goto error; + + /* We're only ever going to care about devices that support + * EGL_EXT_device_drm, so filter out the ones that don't + */ + for (i = 0; i < *num_devices; i++) { + const char *extension_str = + eglQueryDeviceStringEXT(devices[i], EGL_EXTENSIONS); + + if (!epoxy_extension_in_string(extension_str, "EGL_EXT_device_drm")) + continue; + + devices[drm_dev_count++] = devices[i]; + } + if (!drm_dev_count) + goto error; + + *num_devices = drm_dev_count; + tmp = realloc(devices, sizeof(EGLDeviceEXT) * drm_dev_count); + if (!tmp) + goto error; + + devices = tmp; + + return devices; + +error: + free(devices); + + return NULL; +} + +static Bool +xwl_glamor_egl_device_has_egl_extensions(void *device, + const char **ext_list, size_t size) +{ + EGLDisplay egl_display; + int i; + Bool has_exts = TRUE; + + egl_display = glamor_egl_get_display(EGL_PLATFORM_DEVICE_EXT, device); + if (!egl_display || !eglInitialize(egl_display, NULL, NULL)) + return FALSE; + + for (i = 0; i < size; i++) { + if (!epoxy_has_egl_extension(egl_display, ext_list[i])) { + has_exts = FALSE; + break; + } + } + + eglTerminate(egl_display); + return has_exts; +} + +static void +xwl_eglstream_unref_pixmap_stream(struct xwl_pixmap *xwl_pixmap) +{ + struct xwl_screen *xwl_screen = xwl_pixmap->xwl_screen; + + if (--xwl_pixmap->refcount >= 1) + return; + + /* If we're using this stream in the current egl context, unbind it so the + * driver doesn't keep it around until the next eglMakeCurrent() + * don't have to keep it around until something else changes the surface + */ + xwl_glamor_egl_make_current(xwl_screen); + if (eglGetCurrentSurface(EGL_READ) == xwl_pixmap->surface || + eglGetCurrentSurface(EGL_DRAW) == xwl_pixmap->surface) { + eglMakeCurrent(xwl_screen->egl_display, + EGL_NO_SURFACE, EGL_NO_SURFACE, + xwl_screen->egl_context); + } + + if (xwl_pixmap->surface) + eglDestroySurface(xwl_screen->egl_display, xwl_pixmap->surface); + + eglDestroyStreamKHR(xwl_screen->egl_display, xwl_pixmap->stream); + + wl_buffer_destroy(xwl_pixmap->buffer); + free(xwl_pixmap); +} + +static Bool +xwl_glamor_eglstream_destroy_pixmap(PixmapPtr pixmap) +{ + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + + if (xwl_pixmap && pixmap->refcnt == 1) + xwl_eglstream_unref_pixmap_stream(xwl_pixmap); + + return glamor_destroy_pixmap(pixmap); +} + +static struct wl_buffer * +xwl_glamor_eglstream_get_wl_buffer_for_pixmap(PixmapPtr pixmap, + Bool *created) +{ + /* XXX created? */ + return xwl_pixmap_get(pixmap)->buffer; +} + +static void +xwl_eglstream_set_window_pixmap(WindowPtr window, PixmapPtr pixmap) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen); + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); + struct xwl_eglstream_pending_stream *pending; + + pending = xwl_eglstream_window_get_pending(window); + if (pending) { + /* The pixmap for this window has changed before the compositor + * finished attaching the consumer for the window's pixmap's original + * eglstream. A producer can no longer be attached, so the stream's + * useless + */ + pending->is_valid = FALSE; + + /* The compositor may still be using the stream, so we can't destroy + * it yet. We'll only have a guarantee that the stream is safe to + * destroy once we receive the pending wl_display_sync() for this + * stream + */ + pending->xwl_pixmap->refcount++; + } + + xwl_screen->screen->SetWindowPixmap = xwl_eglstream->SetWindowPixmap; + (*xwl_screen->screen->SetWindowPixmap)(window, pixmap); + xwl_eglstream->SetWindowPixmap = xwl_screen->screen->SetWindowPixmap; + xwl_screen->screen->SetWindowPixmap = xwl_eglstream_set_window_pixmap; +} + +/* Because we run asynchronously with our wayland compositor, it's possible + * that an X client event could cause us to begin creating a stream for a + * pixmap/window combo before the stream for the pixmap this window + * previously used has been fully initialized. An example: + * + * - Start processing X client events. + * - X window receives resize event, causing us to create a new pixmap and + * begin creating the corresponding eglstream. This pixmap is known as + * pixmap A. + * - X window receives another resize event, and again changes it's current + * pixmap causing us to create another corresponding eglstream for the same + * window. This pixmap is known as pixmap B. + * - Start handling events from the wayland compositor. + * + * Since both pixmap A and B will have scheduled wl_display_sync events to + * indicate when their respective streams are connected, we will receive each + * callback in the original order the pixmaps were created. This means the + * following would happen: + * + * - Receive pixmap A's stream callback, attach it's stream to the surface of + * the window that just orphaned it. + * - Receive pixmap B's stream callback, fall over and fail because the + * window's surface now incorrectly has pixmap A's stream attached to it. + * + * We work around this problem by keeping a queue of pending streams, and + * only allowing one queue entry to exist for each window. In the scenario + * listed above, this should happen: + * + * - Begin processing X events... + * - A window is resized, causing us to add an eglstream (known as eglstream + * A) waiting for it's consumer to finish attachment to be added to the + * queue. + * - Resize on same window happens. We invalidate the previously pending + * stream and add another one to the pending queue (known as eglstream B). + * - Begin processing Wayland events... + * - Receive invalidated callback from compositor for eglstream A, destroy + * stream. + * - Receive callback from compositor for eglstream B, create producer. + * - Success! + */ +static void +xwl_eglstream_consumer_ready_callback(void *data, + struct wl_callback *callback, + uint32_t time) +{ + struct xwl_screen *xwl_screen = data; + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); + struct xwl_pixmap *xwl_pixmap; + struct xwl_eglstream_pending_stream *pending; + Bool found = FALSE; + + wl_callback_destroy(callback); + + xorg_list_for_each_entry(pending, &xwl_eglstream->pending_streams, link) { + if (pending->cb == callback) { + found = TRUE; + break; + } + } + assert(found); + + if (!pending->is_valid) { + xwl_eglstream_unref_pixmap_stream(pending->xwl_pixmap); + goto out; + } + + xwl_glamor_egl_make_current(xwl_screen); + + xwl_pixmap = pending->xwl_pixmap; + xwl_pixmap->surface = eglCreateStreamProducerSurfaceKHR( + xwl_screen->egl_display, xwl_eglstream->config, + xwl_pixmap->stream, (int[]) { + EGL_WIDTH, pending->pixmap->drawable.width, + EGL_HEIGHT, pending->pixmap->drawable.height, + EGL_NONE + }); + + DebugF("eglstream: win %d completes eglstream for pixmap %p, congrats!\n", + pending->window->drawable.id, pending->pixmap); + + xwl_eglstream_window_set_pending(pending->window, NULL); +out: + xorg_list_del(&pending->link); + free(pending); +} + +static const struct wl_callback_listener consumer_ready_listener = { + xwl_eglstream_consumer_ready_callback +}; + +static void +xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen, + WindowPtr window, PixmapPtr pixmap) +{ + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); + struct xwl_eglstream_pending_stream *pending_stream; + +#ifdef DEBUG + if (!xwl_eglstream_window_get_pending(window)) + DebugF("eglstream: win %d begins new eglstream for pixmap %p\n", + window->drawable.id, pixmap); + else + DebugF("eglstream: win %d interrupts and replaces pending eglstream for pixmap %p\n", + window->drawable.id, pixmap); +#endif + + pending_stream = malloc(sizeof(*pending_stream)); + pending_stream->window = window; + pending_stream->pixmap = pixmap; + pending_stream->xwl_pixmap = xwl_pixmap_get(pixmap); + pending_stream->is_valid = TRUE; + xorg_list_init(&pending_stream->link); + xorg_list_add(&pending_stream->link, &xwl_eglstream->pending_streams); + xwl_eglstream_window_set_pending(window, pending_stream); + + pending_stream->cb = wl_display_sync(xwl_screen->display); + wl_callback_add_listener(pending_stream->cb, &consumer_ready_listener, + xwl_screen); +} + +static void +xwl_eglstream_buffer_release_callback(void *data, struct wl_buffer *wl_buffer) +{ + xwl_eglstream_unref_pixmap_stream(data); +} + +static const struct wl_buffer_listener xwl_eglstream_buffer_release_listener = { + xwl_eglstream_buffer_release_callback +}; + +static void +xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen, + WindowPtr window, PixmapPtr pixmap) +{ + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); + struct xwl_pixmap *xwl_pixmap; + struct xwl_window *xwl_window = xwl_window_from_window(window); + struct wl_array stream_attribs; + int stream_fd = -1; + + xwl_pixmap = calloc(sizeof(*xwl_pixmap), 1); + if (!xwl_pixmap) + FatalError("Not enough memory to create pixmap\n"); + xwl_pixmap_set_private(pixmap, xwl_pixmap); + + xwl_glamor_egl_make_current(xwl_screen); + + xwl_pixmap->xwl_screen = xwl_screen; + xwl_pixmap->refcount = 1; + xwl_pixmap->stream = eglCreateStreamKHR(xwl_screen->egl_display, NULL); + stream_fd = eglGetStreamFileDescriptorKHR(xwl_screen->egl_display, + xwl_pixmap->stream); + + wl_array_init(&stream_attribs); + xwl_pixmap->buffer = + wl_eglstream_display_create_stream(xwl_eglstream->display, + pixmap->drawable.width, + pixmap->drawable.height, + stream_fd, + WL_EGLSTREAM_HANDLE_TYPE_FD, + &stream_attribs); + + wl_buffer_add_listener(xwl_pixmap->buffer, + &xwl_eglstream_buffer_release_listener, + xwl_pixmap); + + wl_eglstream_controller_attach_eglstream_consumer( + xwl_eglstream->controller, xwl_window->surface, xwl_pixmap->buffer); + + xwl_eglstream_queue_pending_stream(xwl_screen, window, pixmap); + + close(stream_fd); +} + +static Bool +xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window) +{ + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + struct xwl_eglstream_pending_stream *pending = + xwl_eglstream_window_get_pending(xwl_window->window); + PixmapPtr pixmap = + (*xwl_screen->screen->GetWindowPixmap)(xwl_window->window); + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + + if (xwl_pixmap) { + if (pending) { + /* Wait for the compositor to finish connecting the consumer for + * this eglstream */ + if (pending->is_valid) + return FALSE; + + /* The pixmap for this window was changed before the compositor + * finished connecting the eglstream for the window's previous + * pixmap. Begin creating a new eglstream. */ + } else { + return TRUE; + } + } + + /* Glamor pixmap has no backing stream yet; begin making one and disallow + * commits until then + */ + xwl_eglstream_create_pending_stream(xwl_screen, xwl_window->window, + pixmap); + + return FALSE; +} + +static void +xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window, + PixmapPtr pixmap, RegionPtr region) +{ + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + BoxPtr box = RegionExtents(region); + EGLint egl_damage[] = { + box->x1, box->y1, + box->x2 - box->x1, box->y2 - box->y1 + }; + GLint saved_vao; + + /* Unbind the framebuffer BEFORE binding the EGLSurface, otherwise we + * won't actually draw to it + */ + xwl_glamor_egl_make_current(xwl_screen); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (eglGetCurrentSurface(EGL_READ) != xwl_pixmap->surface || + eglGetCurrentSurface(EGL_DRAW) != xwl_pixmap->surface) + eglMakeCurrent(xwl_screen->egl_display, + xwl_pixmap->surface, xwl_pixmap->surface, + xwl_screen->egl_context); + + /* Save current GL state */ + glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &saved_vao); + + /* Setup our GL state */ + glUseProgram(xwl_eglstream->blit_prog); + glViewport(0, 0, pixmap->drawable.width, pixmap->drawable.height); + glActiveTexture(GL_TEXTURE0); + glBindVertexArray(xwl_eglstream->blit_vao); + glBindTexture(GL_TEXTURE_2D, glamor_get_pixmap_texture(pixmap)); + + glUniform1i(xwl_eglstream->blit_is_rgba_pos, + pixmap->drawable.depth >= 32); + + /* Blit rendered image into EGLStream surface */ + glDrawBuffer(GL_BACK); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + if (xwl_eglstream->have_egl_damage) + eglSwapBuffersWithDamageKHR(xwl_screen->egl_display, + xwl_pixmap->surface, egl_damage, 1); + else + eglSwapBuffers(xwl_screen->egl_display, xwl_pixmap->surface); + + /* Restore previous state */ + glBindVertexArray(saved_vao); + glBindTexture(GL_TEXTURE_2D, 0); + + /* After this we will hand off the eglstream's wl_buffer to the + * compositor, which will own it until it sends a release() event. */ + xwl_pixmap->refcount++; +} + +static void +xwl_eglstream_display_handle_caps(void *data, + struct wl_eglstream_display *disp, + int32_t caps) +{ + xwl_eglstream_get(data)->display_caps = caps; +} + +static void +xwl_eglstream_display_handle_swapinterval_override(void *data, + struct wl_eglstream_display *disp, + int32_t swapinterval, + struct wl_buffer *stream) +{ +} + +const struct wl_eglstream_display_listener eglstream_display_listener = { + .caps = xwl_eglstream_display_handle_caps, + .swapinterval_override = xwl_eglstream_display_handle_swapinterval_override, +}; + +static Bool +xwl_glamor_eglstream_init_wl_registry(struct xwl_screen *xwl_screen, + struct wl_registry *wl_registry, + uint32_t id, const char *name, + uint32_t version) +{ + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); + + if (strcmp(name, "wl_eglstream_display") == 0) { + xwl_eglstream->display = wl_registry_bind( + wl_registry, id, &wl_eglstream_display_interface, version); + + wl_eglstream_display_add_listener(xwl_eglstream->display, + &eglstream_display_listener, + xwl_screen); + return TRUE; + } else if (strcmp(name, "wl_eglstream_controller") == 0) { + xwl_eglstream->controller = wl_registry_bind( + wl_registry, id, &wl_eglstream_controller_interface, version); + return TRUE; + } + + /* no match */ + return FALSE; +} + +static Bool +xwl_glamor_eglstream_has_wl_interfaces(struct xwl_screen *xwl_screen) +{ + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); + + if (xwl_eglstream->display == NULL) { + ErrorF("glamor: 'wl_eglstream_display' not supported\n"); + return FALSE; + } + + if (xwl_eglstream->controller == NULL) { + ErrorF("glamor: 'wl_eglstream_controller' not supported\n"); + return FALSE; + } + + return TRUE; +} + +static inline void +xwl_eglstream_init_shaders(struct xwl_screen *xwl_screen) +{ + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); + GLint fs, vs, attrib; + GLuint vbo; + + const char *blit_vs_src = + "attribute vec2 texcoord;\n" + "attribute vec2 position;\n" + "varying vec2 t;\n" + "void main() {\n" + " t = texcoord;\n" + " gl_Position = vec4(position, 0, 1);\n" + "}"; + + const char *blit_fs_src = + "varying vec2 t;\n" + "uniform sampler2D s;\n" + "uniform bool is_rgba;\n" + "void main() {\n" + " if (is_rgba)\n" + " gl_FragColor = texture2D(s, t);\n" + " else\n" + " gl_FragColor = vec4(texture2D(s, t).rgb, 1.0);\n" + "}"; + + static const float position[] = { + /* position */ + -1, -1, + 1, -1, + 1, 1, + -1, 1, + /* texcoord */ + 0, 1, + 1, 1, + 1, 0, + 0, 0, + }; + + vs = xwl_eglstream_compile_glsl_prog(GL_VERTEX_SHADER, blit_vs_src); + fs = xwl_eglstream_compile_glsl_prog(GL_FRAGMENT_SHADER, blit_fs_src); + + xwl_eglstream->blit_prog = xwl_eglstream_build_glsl_prog(vs, fs); + glDeleteShader(vs); + glDeleteShader(fs); + + /* Create the blitter's vao */ + glGenVertexArrays(1, &xwl_eglstream->blit_vao); + glBindVertexArray(xwl_eglstream->blit_vao); + + /* Set the data for both position and texcoord in the vbo */ + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(position), position, GL_STATIC_DRAW); + xwl_eglstream->blit_vbo = vbo; + + /* Define each shader attribute's data location in our vbo */ + attrib = glGetAttribLocation(xwl_eglstream->blit_prog, "position"); + glVertexAttribPointer(attrib, 2, GL_FLOAT, TRUE, 0, NULL); + glEnableVertexAttribArray(attrib); + + attrib = glGetAttribLocation(xwl_eglstream->blit_prog, "texcoord"); + glVertexAttribPointer(attrib, 2, GL_FLOAT, TRUE, 0, + (void*)(sizeof(float) * 8)); + glEnableVertexAttribArray(attrib); + + /* Save the location of uniforms we'll set later */ + xwl_eglstream->blit_is_rgba_pos = + glGetUniformLocation(xwl_eglstream->blit_prog, "is_rgba"); +} + +static Bool +xwl_glamor_eglstream_init_egl(struct xwl_screen *xwl_screen) +{ + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); + EGLConfig config; + const EGLint attrib_list[] = { + EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, + EGL_CONTEXT_MAJOR_VERSION_KHR, + GLAMOR_GL_CORE_VER_MAJOR, + EGL_CONTEXT_MINOR_VERSION_KHR, + GLAMOR_GL_CORE_VER_MINOR, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, + EGL_NONE + }; + const EGLint config_attribs[] = { + EGL_SURFACE_TYPE, EGL_STREAM_BIT_KHR, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_NONE, + }; + int n; + + xwl_screen->egl_display = glamor_egl_get_display( + EGL_PLATFORM_DEVICE_EXT, xwl_eglstream->egl_device); + if (!xwl_screen->egl_display) + goto error; + + if (!eglInitialize(xwl_screen->egl_display, NULL, NULL)) { + xwl_screen->egl_display = NULL; + goto error; + } + + if (!epoxy_has_egl_extension(xwl_screen->egl_display, + "EGL_IMG_context_priority")) { + ErrorF("EGL_IMG_context_priority not available\n"); + goto error; + } + + eglChooseConfig(xwl_screen->egl_display, config_attribs, &config, 1, &n); + if (!n) { + ErrorF("No acceptable EGL configs found\n"); + goto error; + } + + xwl_eglstream->config = config; +#if 0 + xwl_screen->formats = + XWL_FORMAT_RGB565 | XWL_FORMAT_XRGB8888 | XWL_FORMAT_ARGB8888; +#endif + + eglBindAPI(EGL_OPENGL_API); + xwl_screen->egl_context = eglCreateContext( + xwl_screen->egl_display, config, EGL_NO_CONTEXT, attrib_list); + if (xwl_screen->egl_context == EGL_NO_CONTEXT) { + ErrorF("Failed to create main EGL context: 0x%x\n", eglGetError()); + goto error; + } + + if (!eglMakeCurrent(xwl_screen->egl_display, + EGL_NO_SURFACE, EGL_NO_SURFACE, + xwl_screen->egl_context)) { + ErrorF("Failed to make EGL context current\n"); + goto error; + } + + xwl_eglstream->have_egl_damage = + epoxy_has_egl_extension(xwl_screen->egl_display, + "EGL_KHR_swap_buffers_with_damage"); + if (!xwl_eglstream->have_egl_damage) + ErrorF("Driver lacks EGL_KHR_swap_buffers_with_damage, performance " + "will be affected\n"); + + xwl_eglstream_init_shaders(xwl_screen); + + return TRUE; +error: + xwl_eglstream_cleanup(xwl_screen); + return FALSE; +} + +static Bool +xwl_glamor_eglstream_init_screen(struct xwl_screen *xwl_screen) +{ + struct xwl_eglstream_private *xwl_eglstream = + xwl_eglstream_get(xwl_screen); + ScreenPtr screen = xwl_screen->screen; + + /* We can just let glamor handle CreatePixmap */ + screen->DestroyPixmap = xwl_glamor_eglstream_destroy_pixmap; + + xwl_eglstream->SetWindowPixmap = screen->SetWindowPixmap; + screen->SetWindowPixmap = xwl_eglstream_set_window_pixmap; + + if (!dixRegisterPrivateKey(&xwl_eglstream_window_private_key, + PRIVATE_WINDOW, 0)) + return FALSE; + + return TRUE; +} + +static EGLDeviceEXT +xwl_eglstream_get_device(struct xwl_screen *xwl_screen) +{ + void **devices = NULL; + const char *exts[] = { + "EGL_KHR_stream", + "EGL_KHR_stream_producer_eglsurface", + }; + int num_devices, i; + EGLDeviceEXT device = EGL_NO_DEVICE_EXT; + + /* No device specified by the user, so find one ourselves */ + devices = xwl_glamor_egl_get_devices(&num_devices); + if (!devices) + goto out; + + for (i = 0; i < num_devices; i++) { + if (xwl_glamor_egl_device_has_egl_extensions(devices[i], exts, + ARRAY_SIZE(exts))) { + device = devices[i]; + break; + } + } + + free(devices); +out: + if (!device) + ErrorF("glamor: No eglstream capable devices found\n"); + return device; +} + +void +xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen) +{ + struct xwl_eglstream_private *xwl_eglstream; + EGLDeviceEXT egl_device; + + xwl_screen->eglstream_backend.is_available = FALSE; + egl_device = xwl_eglstream_get_device(xwl_screen); + if (egl_device == EGL_NO_DEVICE_EXT) + return; + + if (!dixRegisterPrivateKey(&xwl_eglstream_private_key, PRIVATE_SCREEN, 0)) + return; + + xwl_eglstream = calloc(sizeof(*xwl_eglstream), 1); + if (!xwl_eglstream) { + ErrorF("Failed to allocate memory required to init EGLStream support\n"); + return; + } + + dixSetPrivate(&xwl_screen->screen->devPrivates, + &xwl_eglstream_private_key, xwl_eglstream); + + xwl_eglstream->egl_device = egl_device; + xorg_list_init(&xwl_eglstream->pending_streams); + + xwl_screen->eglstream_backend.init_egl = xwl_glamor_eglstream_init_egl; + xwl_screen->eglstream_backend.init_wl_registry = xwl_glamor_eglstream_init_wl_registry; + xwl_screen->eglstream_backend.has_wl_interfaces = xwl_glamor_eglstream_has_wl_interfaces; + xwl_screen->eglstream_backend.init_screen = xwl_glamor_eglstream_init_screen; + xwl_screen->eglstream_backend.get_wl_buffer_for_pixmap = xwl_glamor_eglstream_get_wl_buffer_for_pixmap; + xwl_screen->eglstream_backend.post_damage = xwl_glamor_eglstream_post_damage; + xwl_screen->eglstream_backend.allow_commits = xwl_glamor_eglstream_allow_commits; + xwl_screen->eglstream_backend.is_available = TRUE; +} diff --git a/xserver/hw/xwayland/xwayland-glamor-gbm.c b/xserver/hw/xwayland/xwayland-glamor-gbm.c new file mode 100644 index 000000000..a211e0915 --- /dev/null +++ b/xserver/hw/xwayland/xwayland-glamor-gbm.c @@ -0,0 +1,1035 @@ +/* + * Copyright © 2011-2014 Intel Corporation + * Copyright © 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including + * the next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Lyude Paul <lyude@redhat.com> + * + */ + +#include "xwayland.h" + +#include <fcntl.h> +#include <sys/stat.h> +#include <xf86drm.h> +#include <drm_fourcc.h> + +#define MESA_EGL_NO_X11_HEADERS +#include <gbm.h> +#include <glamor_egl.h> + +#include <glamor.h> +#include <glamor_context.h> +#include <dri3.h> +#include "drm-client-protocol.h" + +struct xwl_gbm_private { + char *device_name; + struct gbm_device *gbm; + struct wl_drm *drm; + struct zwp_linux_dmabuf_v1 *dmabuf; + int drm_fd; + int fd_render_node; + Bool drm_authenticated; + uint32_t capabilities; + int dmabuf_capable; +}; + +struct xwl_pixmap { + struct wl_buffer *buffer; + EGLImage image; + unsigned int texture; + struct gbm_bo *bo; +}; + +static DevPrivateKeyRec xwl_gbm_private_key; +static DevPrivateKeyRec xwl_auth_state_private_key; + +static inline struct xwl_gbm_private * +xwl_gbm_get(struct xwl_screen *xwl_screen) +{ + return dixLookupPrivate(&xwl_screen->screen->devPrivates, + &xwl_gbm_private_key); +} + +static uint32_t +gbm_format_for_depth(int depth) +{ + switch (depth) { + case 16: + return GBM_FORMAT_RGB565; + case 24: + return GBM_FORMAT_XRGB8888; + case 30: + return GBM_FORMAT_ARGB2101010; + default: + ErrorF("unexpected depth: %d\n", depth); + case 32: + return GBM_FORMAT_ARGB8888; + } +} + +static uint32_t +wl_drm_format_for_depth(int depth) +{ + switch (depth) { + case 15: + return WL_DRM_FORMAT_XRGB1555; + case 16: + return WL_DRM_FORMAT_RGB565; + case 24: + return WL_DRM_FORMAT_XRGB8888; + case 30: + return WL_DRM_FORMAT_ARGB2101010; + default: + ErrorF("unexpected depth: %d\n", depth); + case 32: + return WL_DRM_FORMAT_ARGB8888; + } +} + +static char +is_fd_render_node(int fd) +{ + struct stat render; + + if (fstat(fd, &render)) + return 0; + if (!S_ISCHR(render.st_mode)) + return 0; + if (render.st_rdev & 0x80) + return 1; + + return 0; +} + +static char +is_device_path_render_node (const char *device_path) +{ + char is_render_node; + int fd; + + fd = open(device_path, O_RDWR | O_CLOEXEC); + if (fd < 0) + return 0; + + is_render_node = is_fd_render_node(fd); + close(fd); + + return is_render_node; +} + +static PixmapPtr +xwl_glamor_gbm_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, + int depth) +{ + PixmapPtr pixmap; + struct xwl_pixmap *xwl_pixmap; + struct xwl_screen *xwl_screen = xwl_screen_get(screen); + + xwl_pixmap = malloc(sizeof *xwl_pixmap); + if (xwl_pixmap == NULL) + return NULL; + + pixmap = glamor_create_pixmap(screen, + gbm_bo_get_width(bo), + gbm_bo_get_height(bo), + depth, + GLAMOR_CREATE_PIXMAP_NO_TEXTURE); + if (!pixmap) { + free(xwl_pixmap); + return NULL; + } + + xwl_glamor_egl_make_current(xwl_screen); + xwl_pixmap->bo = bo; + xwl_pixmap->buffer = NULL; + xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display, + xwl_screen->egl_context, + EGL_NATIVE_PIXMAP_KHR, + xwl_pixmap->bo, NULL); + + glGenTextures(1, &xwl_pixmap->texture); + glBindTexture(GL_TEXTURE_2D, xwl_pixmap->texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, xwl_pixmap->image); + glBindTexture(GL_TEXTURE_2D, 0); + + xwl_pixmap_set_private(pixmap, xwl_pixmap); + + glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture); + glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM); + + return pixmap; +} + +static PixmapPtr +xwl_glamor_gbm_create_pixmap(ScreenPtr screen, + int width, int height, int depth, + unsigned int hint) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(screen); + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + struct gbm_bo *bo; + + if (width > 0 && height > 0 && depth >= 15 && + (hint == 0 || + hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP || + hint == CREATE_PIXMAP_USAGE_SHARED)) { + uint32_t format = gbm_format_for_depth(depth); + +#ifdef GBM_BO_WITH_MODIFIERS + if (xwl_gbm->dmabuf_capable) { + uint32_t num_modifiers; + uint64_t *modifiers = NULL; + + glamor_get_modifiers(screen, format, &num_modifiers, &modifiers); + bo = gbm_bo_create_with_modifiers(xwl_gbm->gbm, width, height, + format, modifiers, num_modifiers); + free(modifiers); + } + else +#endif + { + bo = gbm_bo_create(xwl_gbm->gbm, width, height, format, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + } + + if (bo) + return xwl_glamor_gbm_create_pixmap_for_bo(screen, bo, depth); + } + + return glamor_create_pixmap(screen, width, height, depth, hint); +} + +static Bool +xwl_glamor_gbm_destroy_pixmap(PixmapPtr pixmap) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen); + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + + if (xwl_pixmap && pixmap->refcnt == 1) { + if (xwl_pixmap->buffer) + wl_buffer_destroy(xwl_pixmap->buffer); + + eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image); + if (xwl_pixmap->bo) + gbm_bo_destroy(xwl_pixmap->bo); + free(xwl_pixmap); + } + + return glamor_destroy_pixmap(pixmap); +} + +static struct wl_buffer * +xwl_glamor_gbm_get_wl_buffer_for_pixmap(PixmapPtr pixmap, + Bool *created) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen); + struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + unsigned short width = pixmap->drawable.width; + unsigned short height = pixmap->drawable.height; + int prime_fd; + int num_planes; + uint32_t strides[4]; + uint32_t offsets[4]; + uint64_t modifier; + int i; + + if (xwl_pixmap == NULL) + return NULL; + + if (xwl_pixmap->buffer) { + /* Buffer already exists. Return it and inform caller if interested. */ + if (created) + *created = FALSE; + return xwl_pixmap->buffer; + } + + /* Buffer does not exist yet. Create now and inform caller if interested. */ + if (created) + *created = TRUE; + + if (!xwl_pixmap->bo) + return NULL; + + prime_fd = gbm_bo_get_fd(xwl_pixmap->bo); + if (prime_fd == -1) + return NULL; + +#ifdef GBM_BO_WITH_MODIFIERS + num_planes = gbm_bo_get_plane_count(xwl_pixmap->bo); + modifier = gbm_bo_get_modifier(xwl_pixmap->bo); + for (i = 0; i < num_planes; i++) { + strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i); + offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i); + } +#else + num_planes = 1; + modifier = DRM_FORMAT_MOD_INVALID; + strides[0] = gbm_bo_get_stride(xwl_pixmap->bo); + offsets[0] = 0; +#endif + + if (xwl_gbm->dmabuf && modifier != DRM_FORMAT_MOD_INVALID) { + struct zwp_linux_buffer_params_v1 *params; + + params = zwp_linux_dmabuf_v1_create_params(xwl_gbm->dmabuf); + for (i = 0; i < num_planes; i++) { + zwp_linux_buffer_params_v1_add(params, prime_fd, i, + offsets[i], strides[i], + modifier >> 32, modifier & 0xffffffff); + } + + xwl_pixmap->buffer = + zwp_linux_buffer_params_v1_create_immed(params, width, height, + wl_drm_format_for_depth(pixmap->drawable.depth), + 0); + zwp_linux_buffer_params_v1_destroy(params); + } else if (num_planes == 1) { + xwl_pixmap->buffer = + wl_drm_create_prime_buffer(xwl_gbm->drm, prime_fd, width, height, + wl_drm_format_for_depth(pixmap->drawable.depth), + 0, gbm_bo_get_stride(xwl_pixmap->bo), + 0, 0, + 0, 0); + } + + close(prime_fd); + return xwl_pixmap->buffer; +} + +static void +xwl_glamor_gbm_cleanup(struct xwl_screen *xwl_screen) +{ + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + + if (xwl_gbm->device_name) + free(xwl_gbm->device_name); + if (xwl_gbm->drm_fd) + close(xwl_gbm->drm_fd); + if (xwl_gbm->drm) + wl_drm_destroy(xwl_gbm->drm); + if (xwl_gbm->gbm) + gbm_device_destroy(xwl_gbm->gbm); + + free(xwl_gbm); +} + +struct xwl_auth_state { + int fd; + ClientPtr client; + struct wl_callback *callback; +}; + +static void +free_xwl_auth_state(ClientPtr pClient, struct xwl_auth_state *state) +{ + dixSetPrivate(&pClient->devPrivates, &xwl_auth_state_private_key, NULL); + if (state) { + wl_callback_destroy(state->callback); + free(state); + } +} + +static void +xwl_auth_state_client_callback(CallbackListPtr *pcbl, void *unused, void *data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + struct xwl_auth_state *state; + + switch (pClient->clientState) { + case ClientStateGone: + case ClientStateRetained: + state = dixLookupPrivate(&pClient->devPrivates, + &xwl_auth_state_private_key); + free_xwl_auth_state(pClient, state); + break; + default: + break; + } +} + +static void +sync_callback(void *data, struct wl_callback *callback, uint32_t serial) +{ + struct xwl_auth_state *state = data; + ClientPtr client = state->client; + + /* if the client is gone, the callback is cancelled so it's safe to + * assume the client is still in ClientStateRunning at this point... + */ + dri3_send_open_reply(client, state->fd); + AttendClient(client); + free_xwl_auth_state(client, state); +} + +static const struct wl_callback_listener sync_listener = { + sync_callback +}; + +static int +xwl_dri3_open_client(ClientPtr client, + ScreenPtr screen, + RRProviderPtr provider, + int *pfd) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(screen); + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + struct xwl_auth_state *state; + drm_magic_t magic; + int fd; + + fd = open(xwl_gbm->device_name, O_RDWR | O_CLOEXEC); + if (fd < 0) + return BadAlloc; + if (xwl_gbm->fd_render_node) { + *pfd = fd; + return Success; + } + + state = malloc(sizeof *state); + if (state == NULL) { + close(fd); + return BadAlloc; + } + + state->client = client; + state->fd = fd; + + if (drmGetMagic(state->fd, &magic) < 0) { + close(state->fd); + free(state); + return BadMatch; + } + + wl_drm_authenticate(xwl_gbm->drm, magic); + state->callback = wl_display_sync(xwl_screen->display); + wl_callback_add_listener(state->callback, &sync_listener, state); + dixSetPrivate(&client->devPrivates, &xwl_auth_state_private_key, state); + + IgnoreClient(client); + + return Success; +} + +_X_EXPORT PixmapPtr +glamor_pixmap_from_fds(ScreenPtr screen, CARD8 num_fds, const int *fds, + CARD16 width, CARD16 height, + const CARD32 *strides, const CARD32 *offsets, + CARD8 depth, CARD8 bpp, uint64_t modifier) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(screen); + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + struct gbm_bo *bo = NULL; + PixmapPtr pixmap; + int i; + + if (width == 0 || height == 0 || num_fds == 0 || + depth < 15 || bpp != BitsPerPixel(depth) || + strides[0] < width * bpp / 8) + goto error; + + if (xwl_gbm->dmabuf_capable && modifier != DRM_FORMAT_MOD_INVALID) { +#ifdef GBM_BO_WITH_MODIFIERS + struct gbm_import_fd_modifier_data data; + + data.width = width; + data.height = height; + data.num_fds = num_fds; + data.format = gbm_format_for_depth(depth); + data.modifier = modifier; + for (i = 0; i < num_fds; i++) { + data.fds[i] = fds[i]; + data.strides[i] = strides[i]; + data.offsets[i] = offsets[i]; + } + bo = gbm_bo_import(xwl_gbm->gbm, GBM_BO_IMPORT_FD_MODIFIER, &data, 0); +#endif + } else if (num_fds == 1) { + struct gbm_import_fd_data data; + + data.fd = fds[0]; + data.width = width; + data.height = height; + data.stride = strides[0]; + data.format = gbm_format_for_depth(depth); + bo = gbm_bo_import(xwl_gbm->gbm, GBM_BO_IMPORT_FD, &data, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + } else { + goto error; + } + + if (bo == NULL) + goto error; + + pixmap = xwl_glamor_gbm_create_pixmap_for_bo(screen, bo, depth); + if (pixmap == NULL) { + gbm_bo_destroy(bo); + goto error; + } + + return pixmap; + +error: + return NULL; +} + +_X_EXPORT int +glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, + uint32_t *strides, uint32_t *offsets, + uint64_t *modifier) +{ + struct xwl_pixmap *xwl_pixmap; +#ifdef GBM_BO_WITH_MODIFIERS + uint32_t num_fds; + int i; +#endif + + xwl_pixmap = xwl_pixmap_get(pixmap); + + if (xwl_pixmap == NULL) + return 0; + + if (!xwl_pixmap->bo) + return 0; + +#ifdef GBM_BO_WITH_MODIFIERS + num_fds = gbm_bo_get_plane_count(xwl_pixmap->bo); + *modifier = gbm_bo_get_modifier(xwl_pixmap->bo); + + for (i = 0; i < num_fds; i++) { + fds[i] = gbm_bo_get_fd(xwl_pixmap->bo); + strides[i] = gbm_bo_get_stride_for_plane(xwl_pixmap->bo, i); + offsets[i] = gbm_bo_get_offset(xwl_pixmap->bo, i); + } + + return num_fds; +#else + *modifier = DRM_FORMAT_MOD_INVALID; + fds[0] = gbm_bo_get_fd(xwl_pixmap->bo); + strides[0] = gbm_bo_get_stride(xwl_pixmap->bo); + offsets[0] = 0; + return 1; +#endif +} + +/* Not actually used, just defined here so there's something for + * _glamor_egl_fds_from_pixmap() to link against + */ +_X_EXPORT int +glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, + CARD16 *stride, CARD32 *size) +{ + return -1; +} + +_X_EXPORT Bool +glamor_get_formats(ScreenPtr screen, + CARD32 *num_formats, CARD32 **formats) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(screen); + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + int i; + + /* Explicitly zero the count as the caller may ignore the return value */ + *num_formats = 0; + + if (!xwl_gbm->dmabuf_capable || !xwl_gbm->dmabuf) + return FALSE; + + if (xwl_screen->num_formats == 0) + return TRUE; + + *formats = calloc(xwl_screen->num_formats, sizeof(CARD32)); + if (*formats == NULL) + return FALSE; + + for (i = 0; i < xwl_screen->num_formats; i++) + (*formats)[i] = xwl_screen->formats[i].format; + *num_formats = xwl_screen->num_formats; + + return TRUE; +} + +_X_EXPORT Bool +glamor_get_modifiers(ScreenPtr screen, uint32_t format, + uint32_t *num_modifiers, uint64_t **modifiers) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(screen); + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + struct xwl_format *xwl_format = NULL; + int i; + + /* Explicitly zero the count as the caller may ignore the return value */ + *num_modifiers = 0; + + if (!xwl_gbm->dmabuf_capable || !xwl_gbm->dmabuf) + return FALSE; + + if (xwl_screen->num_formats == 0) + return TRUE; + + for (i = 0; i < xwl_screen->num_formats; i++) { + if (xwl_screen->formats[i].format == format) { + xwl_format = &xwl_screen->formats[i]; + break; + } + } + + if (!xwl_format) + return FALSE; + + *modifiers = calloc(xwl_format->num_modifiers, sizeof(uint64_t)); + if (*modifiers == NULL) + return FALSE; + + for (i = 0; i < xwl_format->num_modifiers; i++) + (*modifiers)[i] = xwl_format->modifiers[i]; + *num_modifiers = xwl_format->num_modifiers; + + return TRUE; +} + +static const dri3_screen_info_rec xwl_dri3_info = { + .version = 2, + .open = NULL, + .pixmap_from_fds = glamor_pixmap_from_fds, + .fds_from_pixmap = glamor_fds_from_pixmap, + .open_client = xwl_dri3_open_client, + .get_formats = glamor_get_formats, + .get_modifiers = glamor_get_modifiers, + .get_drawable_modifiers = glamor_get_drawable_modifiers, +}; + +static const char * +get_render_node_path_for_device(const drmDevicePtr drm_device, + const char *device_path) +{ + char *render_node_path = NULL; + char device_found = 0; + int i; + + for (i = 0; i < DRM_NODE_MAX; i++) { + if ((drm_device->available_nodes & (1 << i)) == 0) + continue; + + if (!strcmp (device_path, drm_device->nodes[i])) + device_found = 1; + + if (is_device_path_render_node(drm_device->nodes[i])) + render_node_path = drm_device->nodes[i]; + + if (device_found && render_node_path) + return render_node_path; + } + + return NULL; +} + +static char * +get_render_node_path(const char *device_path) +{ + drmDevicePtr *devices = NULL; + char *render_node_path = NULL; + int i, n_devices, max_devices; + + max_devices = drmGetDevices2(0, NULL, 0); + if (max_devices <= 0) + goto out; + + devices = calloc(max_devices, sizeof(drmDevicePtr)); + if (!devices) + goto out; + + n_devices = drmGetDevices2(0, devices, max_devices); + if (n_devices < 0) + goto out; + + for (i = 0; i < n_devices; i++) { + const char *node_path = get_render_node_path_for_device(devices[i], + device_path); + if (node_path) { + render_node_path = strdup(node_path); + break; + } + } + +out: + free(devices); + return render_node_path; +} + +static void +xwl_drm_handle_device(void *data, struct wl_drm *drm, const char *device) +{ + struct xwl_screen *xwl_screen = data; + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + drm_magic_t magic; + char *render_node_path = NULL; + + if (!is_device_path_render_node(device)) + render_node_path = get_render_node_path(device); + + if (render_node_path) + xwl_gbm->device_name = render_node_path; + else + xwl_gbm->device_name = strdup(device); + + if (!xwl_gbm->device_name) { + xwl_glamor_gbm_cleanup(xwl_screen); + return; + } + + xwl_gbm->drm_fd = open(xwl_gbm->device_name, O_RDWR | O_CLOEXEC); + if (xwl_gbm->drm_fd == -1) { + ErrorF("wayland-egl: could not open %s (%s)\n", + xwl_gbm->device_name, strerror(errno)); + xwl_glamor_gbm_cleanup(xwl_screen); + return; + } + + if (is_fd_render_node(xwl_gbm->drm_fd)) { + xwl_gbm->fd_render_node = 1; + xwl_screen->expecting_event--; + } else { + drmGetMagic(xwl_gbm->drm_fd, &magic); + wl_drm_authenticate(xwl_gbm->drm, magic); + } +} + +static void +xwl_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) +{ +} + +static void +xwl_drm_handle_authenticated(void *data, struct wl_drm *drm) +{ + struct xwl_screen *xwl_screen = data; + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + + xwl_gbm->drm_authenticated = TRUE; + xwl_screen->expecting_event--; +} + +static void +xwl_drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value) +{ + xwl_gbm_get(data)->capabilities = value; +} + +static const struct wl_drm_listener xwl_drm_listener = { + xwl_drm_handle_device, + xwl_drm_handle_format, + xwl_drm_handle_authenticated, + xwl_drm_handle_capabilities +}; + +static void +xwl_dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, + uint32_t format) +{ +} + +static void +xwl_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, + uint32_t format, uint32_t modifier_hi, + uint32_t modifier_lo) +{ + struct xwl_screen *xwl_screen = data; + struct xwl_format *xwl_format = NULL; + int i; + + for (i = 0; i < xwl_screen->num_formats; i++) { + if (xwl_screen->formats[i].format == format) { + xwl_format = &xwl_screen->formats[i]; + break; + } + } + + if (xwl_format == NULL) { + xwl_screen->num_formats++; + xwl_screen->formats = realloc(xwl_screen->formats, + xwl_screen->num_formats * sizeof(*xwl_format)); + if (!xwl_screen->formats) + return; + xwl_format = &xwl_screen->formats[xwl_screen->num_formats - 1]; + xwl_format->format = format; + xwl_format->num_modifiers = 0; + xwl_format->modifiers = NULL; + } + + xwl_format->num_modifiers++; + xwl_format->modifiers = realloc(xwl_format->modifiers, + xwl_format->num_modifiers * sizeof(uint64_t)); + if (!xwl_format->modifiers) + return; + xwl_format->modifiers[xwl_format->num_modifiers - 1] = (uint64_t) modifier_lo; + xwl_format->modifiers[xwl_format->num_modifiers - 1] |= (uint64_t) modifier_hi << 32; +} + +static const struct zwp_linux_dmabuf_v1_listener xwl_dmabuf_listener = { + .format = xwl_dmabuf_handle_format, + .modifier = xwl_dmabuf_handle_modifier +}; + +Bool +xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version) +{ + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + + if (version < 2) + return FALSE; + + xwl_gbm->drm = + wl_registry_bind(xwl_screen->registry, id, &wl_drm_interface, 2); + wl_drm_add_listener(xwl_gbm->drm, &xwl_drm_listener, xwl_screen); + xwl_screen->expecting_event++; + + return TRUE; +} + +Bool +xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version) +{ + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + + if (version < 3) + return FALSE; + + xwl_gbm->dmabuf = + wl_registry_bind(xwl_screen->registry, id, &zwp_linux_dmabuf_v1_interface, 3); + zwp_linux_dmabuf_v1_add_listener(xwl_gbm->dmabuf, &xwl_dmabuf_listener, xwl_screen); + + return TRUE; +} + +static Bool +xwl_glamor_gbm_init_wl_registry(struct xwl_screen *xwl_screen, + struct wl_registry *wl_registry, + uint32_t id, const char *name, + uint32_t version) +{ + if (strcmp(name, "wl_drm") == 0) { + xwl_screen_set_drm_interface(xwl_screen, id, version); + return TRUE; + } else if (strcmp(name, "zwp_linux_dmabuf_v1") == 0) { + xwl_screen_set_dmabuf_interface(xwl_screen, id, version); + return TRUE; + } + + /* no match */ + return FALSE; +} + +static Bool +xwl_glamor_gbm_has_egl_extension(void) +{ + return (epoxy_has_egl_extension(NULL, "EGL_MESA_platform_gbm") || + epoxy_has_egl_extension(NULL, "EGL_KHR_platform_gbm")); +} + +static Bool +xwl_glamor_gbm_has_wl_interfaces(struct xwl_screen *xwl_screen) +{ + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + + if (xwl_gbm->drm == NULL) { + ErrorF("glamor: 'wl_drm' not supported\n"); + return FALSE; + } + + return TRUE; +} + +static Bool +xwl_glamor_gbm_init_egl(struct xwl_screen *xwl_screen) +{ + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + EGLint major, minor; + Bool egl_initialized = FALSE; + static const EGLint config_attribs_core[] = { + EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, + EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, + EGL_CONTEXT_MAJOR_VERSION_KHR, + GLAMOR_GL_CORE_VER_MAJOR, + EGL_CONTEXT_MINOR_VERSION_KHR, + GLAMOR_GL_CORE_VER_MINOR, + EGL_NONE + }; + const GLubyte *renderer; + + if (!xwl_gbm->fd_render_node && !xwl_gbm->drm_authenticated) { + ErrorF("Failed to get wl_drm, disabling Glamor and DRI3\n"); + return FALSE; + } + + xwl_gbm->gbm = gbm_create_device(xwl_gbm->drm_fd); + if (!xwl_gbm->gbm) { + ErrorF("couldn't create gbm device\n"); + goto error; + } + + xwl_screen->egl_display = glamor_egl_get_display(EGL_PLATFORM_GBM_MESA, + xwl_gbm->gbm); + if (xwl_screen->egl_display == EGL_NO_DISPLAY) { + ErrorF("glamor_egl_get_display() failed\n"); + goto error; + } + + egl_initialized = eglInitialize(xwl_screen->egl_display, &major, &minor); + if (!egl_initialized) { + ErrorF("eglInitialize() failed\n"); + goto error; + } + + eglBindAPI(EGL_OPENGL_API); + + xwl_screen->egl_context = eglCreateContext( + xwl_screen->egl_display, NULL, EGL_NO_CONTEXT, config_attribs_core); + if (xwl_screen->egl_context == EGL_NO_CONTEXT) { + xwl_screen->egl_context = eglCreateContext( + xwl_screen->egl_display, NULL, EGL_NO_CONTEXT, NULL); + } + + if (xwl_screen->egl_context == EGL_NO_CONTEXT) { + ErrorF("Failed to create EGL context\n"); + goto error; + } + + if (!eglMakeCurrent(xwl_screen->egl_display, + EGL_NO_SURFACE, EGL_NO_SURFACE, + xwl_screen->egl_context)) { + ErrorF("Failed to make EGL context current\n"); + goto error; + } + + renderer = glGetString(GL_RENDERER); + if (!renderer) { + ErrorF("glGetString() returned NULL, your GL is broken\n"); + goto error; + } + if (strstr((const char *)renderer, "llvmpipe")) { + ErrorF("Refusing to try glamor on llvmpipe\n"); + goto error; + } + + if (!epoxy_has_gl_extension("GL_OES_EGL_image")) { + ErrorF("GL_OES_EGL_image not available\n"); + goto error; + } + + if (epoxy_has_egl_extension(xwl_screen->egl_display, + "EXT_image_dma_buf_import") && + epoxy_has_egl_extension(xwl_screen->egl_display, + "EXT_image_dma_buf_import_modifiers")) + xwl_gbm->dmabuf_capable = TRUE; + + return TRUE; +error: + if (xwl_screen->egl_context != EGL_NO_CONTEXT) { + eglDestroyContext(xwl_screen->egl_display, xwl_screen->egl_context); + xwl_screen->egl_context = EGL_NO_CONTEXT; + } + + if (xwl_screen->egl_display != EGL_NO_DISPLAY) { + eglTerminate(xwl_screen->egl_display); + xwl_screen->egl_display = EGL_NO_DISPLAY; + } + + xwl_glamor_gbm_cleanup(xwl_screen); + return FALSE; +} + +static Bool +xwl_glamor_gbm_init_screen(struct xwl_screen *xwl_screen) +{ + struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); + + if (!dri3_screen_init(xwl_screen->screen, &xwl_dri3_info)) { + ErrorF("Failed to initialize dri3\n"); + goto error; + } + + if (xwl_gbm->fd_render_node) + goto skip_drm_auth; + + if (!dixRegisterPrivateKey(&xwl_auth_state_private_key, PRIVATE_CLIENT, + 0)) { + ErrorF("Failed to register private key\n"); + goto error; + } + + if (!AddCallback(&ClientStateCallback, xwl_auth_state_client_callback, + NULL)) { + ErrorF("Failed to add client state callback\n"); + goto error; + } + +skip_drm_auth: + xwl_screen->screen->CreatePixmap = xwl_glamor_gbm_create_pixmap; + xwl_screen->screen->DestroyPixmap = xwl_glamor_gbm_destroy_pixmap; + + return TRUE; +error: + xwl_glamor_gbm_cleanup(xwl_screen); + return FALSE; +} + +void +xwl_glamor_init_gbm(struct xwl_screen *xwl_screen) +{ + struct xwl_gbm_private *xwl_gbm; + + xwl_screen->gbm_backend.is_available = FALSE; + + if (!xwl_glamor_gbm_has_egl_extension()) + return; + + if (!dixRegisterPrivateKey(&xwl_gbm_private_key, PRIVATE_SCREEN, 0)) + return; + + xwl_gbm = calloc(sizeof(*xwl_gbm), 1); + if (!xwl_gbm) { + ErrorF("glamor: Not enough memory to setup GBM, disabling\n"); + return; + } + + dixSetPrivate(&xwl_screen->screen->devPrivates, &xwl_gbm_private_key, + xwl_gbm); + + xwl_screen->gbm_backend.init_wl_registry = xwl_glamor_gbm_init_wl_registry; + xwl_screen->gbm_backend.has_wl_interfaces = xwl_glamor_gbm_has_wl_interfaces; + xwl_screen->gbm_backend.init_egl = xwl_glamor_gbm_init_egl; + xwl_screen->gbm_backend.init_screen = xwl_glamor_gbm_init_screen; + xwl_screen->gbm_backend.get_wl_buffer_for_pixmap = xwl_glamor_gbm_get_wl_buffer_for_pixmap; + xwl_screen->gbm_backend.is_available = TRUE; +} diff --git a/xserver/hw/xwayland/xwayland-glamor-xv.c b/xserver/hw/xwayland/xwayland-glamor-xv.c index 65f93c693..8e0f8da94 100644 --- a/xserver/hw/xwayland/xwayland-glamor-xv.c +++ b/xserver/hw/xwayland/xwayland-glamor-xv.c @@ -213,7 +213,7 @@ xwl_glamor_xv_add_formats(XvAdaptorPtr pa) void *moreSpace; totFormat *= 2; - moreSpace = XNFreallocarray(pFormat, totFormat, + moreSpace = xnfreallocarray(pFormat, totFormat, sizeof(XvFormatRec)); pFormat = moreSpace; pf = pFormat + numFormat; diff --git a/xserver/hw/xwayland/xwayland-glamor.c b/xserver/hw/xwayland/xwayland-glamor.c index 63f230369..7ea6def61 100644 --- a/xserver/hw/xwayland/xwayland-glamor.c +++ b/xserver/hw/xwayland/xwayland-glamor.c @@ -25,30 +25,14 @@ #include "xwayland.h" -#include <fcntl.h> -#include <sys/stat.h> -#include <xf86drm.h> - #define MESA_EGL_NO_X11_HEADERS -#include <gbm.h> #include <glamor_egl.h> #include <glamor.h> #include <glamor_context.h> -#include <dri3.h> -#include "drm-client-protocol.h" - -static DevPrivateKeyRec xwl_auth_state_private_key; - -struct xwl_pixmap { - struct wl_buffer *buffer; - struct gbm_bo *bo; - void *image; - unsigned int texture; -}; static void -xwl_glamor_egl_make_current(struct glamor_context *glamor_ctx) +glamor_egl_make_current(struct glamor_context *glamor_ctx) { eglMakeCurrent(glamor_ctx->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); @@ -58,36 +42,14 @@ xwl_glamor_egl_make_current(struct glamor_context *glamor_ctx) FatalError("Failed to make EGL context current\n"); } -static uint32_t -drm_format_for_depth(int depth) +void +xwl_glamor_egl_make_current(struct xwl_screen *xwl_screen) { - switch (depth) { - case 15: - return WL_DRM_FORMAT_XRGB1555; - case 16: - return WL_DRM_FORMAT_RGB565; - case 24: - return WL_DRM_FORMAT_XRGB8888; - default: - ErrorF("unexpected depth: %d\n", depth); - case 32: - return WL_DRM_FORMAT_ARGB8888; - } -} + if (lastGLContext == xwl_screen->glamor_ctx) + return; -static uint32_t -gbm_format_for_depth(int depth) -{ - switch (depth) { - case 16: - return GBM_FORMAT_RGB565; - case 24: - return GBM_FORMAT_XRGB8888; - default: - ErrorF("unexpected depth: %d\n", depth); - case 32: - return GBM_FORMAT_ARGB8888; - } + lastGLContext = xwl_screen->glamor_ctx; + xwl_screen->glamor_ctx->make_current(xwl_screen->glamor_ctx); } void @@ -95,129 +57,74 @@ glamor_egl_screen_init(ScreenPtr screen, struct glamor_context *glamor_ctx) { struct xwl_screen *xwl_screen = xwl_screen_get(screen); + glamor_enable_dri3(screen); glamor_ctx->ctx = xwl_screen->egl_context; glamor_ctx->display = xwl_screen->egl_display; - glamor_ctx->make_current = xwl_glamor_egl_make_current; + glamor_ctx->make_current = glamor_egl_make_current; xwl_screen->glamor_ctx = glamor_ctx; } -static PixmapPtr -xwl_glamor_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, int depth) +void +xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen, + struct wl_registry *registry, + uint32_t id, const char *interface, + uint32_t version) { - PixmapPtr pixmap; - struct xwl_pixmap *xwl_pixmap; - struct xwl_screen *xwl_screen = xwl_screen_get(screen); - - xwl_pixmap = malloc(sizeof *xwl_pixmap); - if (xwl_pixmap == NULL) - return NULL; - - pixmap = glamor_create_pixmap(screen, - gbm_bo_get_width(bo), - gbm_bo_get_height(bo), - depth, - GLAMOR_CREATE_PIXMAP_NO_TEXTURE); - if (pixmap == NULL) { - free(xwl_pixmap); - return NULL; - } - - if (lastGLContext != xwl_screen->glamor_ctx) { - lastGLContext = xwl_screen->glamor_ctx; - xwl_glamor_egl_make_current(xwl_screen->glamor_ctx); - } - - xwl_pixmap->bo = bo; - xwl_pixmap->buffer = NULL; - xwl_pixmap->image = eglCreateImageKHR(xwl_screen->egl_display, - xwl_screen->egl_context, - EGL_NATIVE_PIXMAP_KHR, - xwl_pixmap->bo, NULL); - - glGenTextures(1, &xwl_pixmap->texture); - glBindTexture(GL_TEXTURE_2D, xwl_pixmap->texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, xwl_pixmap->image); - glBindTexture(GL_TEXTURE_2D, 0); - - xwl_pixmap_set_private(pixmap, xwl_pixmap); - - glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture); - glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM); + if (xwl_screen->gbm_backend.is_available && + xwl_screen->gbm_backend.init_wl_registry(xwl_screen, + registry, + id, + interface, + version)); /* no-op */ + else if (xwl_screen->eglstream_backend.is_available && + xwl_screen->eglstream_backend.init_wl_registry(xwl_screen, + registry, + id, + interface, + version)); /* no-op */ +} - return pixmap; +Bool +xwl_glamor_has_wl_interfaces(struct xwl_screen *xwl_screen, + struct xwl_egl_backend *xwl_egl_backend) +{ + return xwl_egl_backend->has_wl_interfaces(xwl_screen); } struct wl_buffer * -xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap) +xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap, + Bool *created) { struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen); - struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); - int prime_fd; - if (xwl_pixmap->buffer) - return xwl_pixmap->buffer; + if (xwl_screen->egl_backend->get_wl_buffer_for_pixmap) + return xwl_screen->egl_backend->get_wl_buffer_for_pixmap(pixmap, + created); - prime_fd = gbm_bo_get_fd(xwl_pixmap->bo); - if (prime_fd == -1) - return NULL; - - xwl_pixmap->buffer = - wl_drm_create_prime_buffer(xwl_screen->drm, prime_fd, - pixmap->drawable.width, - pixmap->drawable.height, - drm_format_for_depth(pixmap->drawable.depth), - 0, gbm_bo_get_stride(xwl_pixmap->bo), - 0, 0, - 0, 0); - - close(prime_fd); - - return xwl_pixmap->buffer; + return NULL; } -static PixmapPtr -xwl_glamor_create_pixmap(ScreenPtr screen, - int width, int height, int depth, unsigned int hint) +void +xwl_glamor_post_damage(struct xwl_window *xwl_window, + PixmapPtr pixmap, RegionPtr region) { - struct xwl_screen *xwl_screen = xwl_screen_get(screen); - struct gbm_bo *bo; - - if (width > 0 && height > 0 && depth >= 15 && - (hint == 0 || - hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP || - hint == CREATE_PIXMAP_USAGE_SHARED)) { - bo = gbm_bo_create(xwl_screen->gbm, width, height, - gbm_format_for_depth(depth), - GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); - - if (bo) - return xwl_glamor_create_pixmap_for_bo(screen, bo, depth); - } + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; - return glamor_create_pixmap(screen, width, height, depth, hint); + if (xwl_screen->egl_backend->post_damage) + xwl_screen->egl_backend->post_damage(xwl_window, pixmap, region); } -static Bool -xwl_glamor_destroy_pixmap(PixmapPtr pixmap) +Bool +xwl_glamor_allow_commits(struct xwl_window *xwl_window) { - struct xwl_screen *xwl_screen = xwl_screen_get(pixmap->drawable.pScreen); - struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap); - - if (xwl_pixmap && pixmap->refcnt == 1) { - if (xwl_pixmap->buffer) - wl_buffer_destroy(xwl_pixmap->buffer); - - eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image); - gbm_bo_destroy(xwl_pixmap->bo); - free(xwl_pixmap); - } + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; - return glamor_destroy_pixmap(pixmap); + if (xwl_screen->egl_backend->allow_commits) + return xwl_screen->egl_backend->allow_commits(xwl_window); + else + return TRUE; } static Bool @@ -239,12 +146,9 @@ xwl_glamor_create_screen_resources(ScreenPtr screen) fbCreatePixmap(screen, 0, 0, screen->rootDepth, 0); } else { - screen->devPrivate = - xwl_glamor_create_pixmap(screen, screen->width, screen->height, - screen->rootDepth, - CREATE_PIXMAP_USAGE_BACKING_PIXMAP); - if (screen->devPrivate) - glamor_set_screen_pixmap(screen->devPrivate, NULL); + screen->devPrivate = screen->CreatePixmap( + screen, screen->width, screen->height, screen->rootDepth, + CREATE_PIXMAP_USAGE_BACKING_PIXMAP); } SetRootClip(screen, xwl_screen->root_clip_mode); @@ -252,367 +156,105 @@ xwl_glamor_create_screen_resources(ScreenPtr screen) return screen->devPrivate != NULL; } -static char -is_fd_render_node(int fd) -{ - struct stat render; - - if (fstat(fd, &render)) - return 0; - if (!S_ISCHR(render.st_mode)) - return 0; - if (render.st_rdev & 0x80) - return 1; - - return 0; -} - -static void -xwl_drm_init_egl(struct xwl_screen *xwl_screen) -{ - EGLint major, minor; - const char *version; - static const EGLint config_attribs_core[] = { - EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, - EGL_CONTEXT_MAJOR_VERSION_KHR, - GLAMOR_GL_CORE_VER_MAJOR, - EGL_CONTEXT_MINOR_VERSION_KHR, - GLAMOR_GL_CORE_VER_MINOR, - EGL_NONE - }; - - if (xwl_screen->egl_display) - return; - - xwl_screen->expecting_event--; - - xwl_screen->gbm = gbm_create_device(xwl_screen->drm_fd); - if (xwl_screen->gbm == NULL) { - ErrorF("couldn't get display device\n"); - return; - } - - xwl_screen->egl_display = glamor_egl_get_display(EGL_PLATFORM_GBM_MESA, - xwl_screen->gbm); - if (xwl_screen->egl_display == EGL_NO_DISPLAY) { - ErrorF("glamor_egl_get_display() failed\n"); - return; - } - - if (!eglInitialize(xwl_screen->egl_display, &major, &minor)) { - ErrorF("eglInitialize() failed\n"); - return; - } - - eglBindAPI(EGL_OPENGL_API); - - version = eglQueryString(xwl_screen->egl_display, EGL_VERSION); - ErrorF("glamor: EGL version %s:\n", version); - - xwl_screen->egl_context = eglCreateContext(xwl_screen->egl_display, - NULL, EGL_NO_CONTEXT, config_attribs_core); - if (!xwl_screen->egl_context) - xwl_screen->egl_context = eglCreateContext(xwl_screen->egl_display, - NULL, EGL_NO_CONTEXT, NULL); - - if (xwl_screen->egl_context == EGL_NO_CONTEXT) { - ErrorF("Failed to create EGL context\n"); - return; - } - - if (!eglMakeCurrent(xwl_screen->egl_display, - EGL_NO_SURFACE, EGL_NO_SURFACE, - xwl_screen->egl_context)) { - ErrorF("Failed to make EGL context current\n"); - return; - } - - if (!epoxy_has_gl_extension("GL_OES_EGL_image")) { - ErrorF("GL_OES_EGL_image not available\n"); - return; - } - - return; -} - -static void -xwl_drm_handle_device(void *data, struct wl_drm *drm, const char *device) -{ - struct xwl_screen *xwl_screen = data; - drm_magic_t magic; - - xwl_screen->device_name = strdup(device); - if (!xwl_screen->device_name) - return; - - xwl_screen->drm_fd = open(xwl_screen->device_name, O_RDWR | O_CLOEXEC); - if (xwl_screen->drm_fd == -1) { - ErrorF("wayland-egl: could not open %s (%s)\n", - xwl_screen->device_name, strerror(errno)); - return; - } - - if (is_fd_render_node(xwl_screen->drm_fd)) { - xwl_screen->fd_render_node = 1; - xwl_drm_init_egl(xwl_screen); - } else { - drmGetMagic(xwl_screen->drm_fd, &magic); - wl_drm_authenticate(xwl_screen->drm, magic); - } -} - -static void -xwl_drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) -{ - struct xwl_screen *xwl_screen = data; - - switch (format) { - case WL_DRM_FORMAT_ARGB8888: - xwl_screen->formats |= XWL_FORMAT_ARGB8888; - break; - case WL_DRM_FORMAT_XRGB8888: - xwl_screen->formats |= XWL_FORMAT_XRGB8888; - break; - case WL_DRM_FORMAT_RGB565: - xwl_screen->formats |= XWL_FORMAT_RGB565; - break; - } -} - -static void -xwl_drm_handle_authenticated(void *data, struct wl_drm *drm) -{ - struct xwl_screen *xwl_screen = data; - - if (!xwl_screen->egl_display) - xwl_drm_init_egl(xwl_screen); -} - -static void -xwl_drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value) -{ - struct xwl_screen *xwl_screen = data; - - xwl_screen->capabilities = value; -} - -static const struct wl_drm_listener xwl_drm_listener = { - xwl_drm_handle_device, - xwl_drm_handle_format, - xwl_drm_handle_authenticated, - xwl_drm_handle_capabilities -}; - -Bool -xwl_screen_init_glamor(struct xwl_screen *xwl_screen, - uint32_t id, uint32_t version) -{ - if (version < 2) - return FALSE; - - xwl_screen->drm = - wl_registry_bind(xwl_screen->registry, id, &wl_drm_interface, 2); - wl_drm_add_listener(xwl_screen->drm, &xwl_drm_listener, xwl_screen); - xwl_screen->expecting_event++; - - return TRUE; -} - int -glamor_egl_dri3_fd_name_from_tex(ScreenPtr screen, - PixmapPtr pixmap, - unsigned int tex, - Bool want_name, CARD16 *stride, CARD32 *size) +glamor_egl_fd_name_from_pixmap(ScreenPtr screen, + PixmapPtr pixmap, + CARD16 *stride, CARD32 *size) { return 0; } -struct xwl_auth_state { - int fd; - ClientPtr client; - struct wl_callback *callback; -}; - -static void -free_xwl_auth_state(ClientPtr pClient, struct xwl_auth_state *state) +void +xwl_glamor_init_backends(struct xwl_screen *xwl_screen, Bool use_eglstream) { - dixSetPrivate(&pClient->devPrivates, &xwl_auth_state_private_key, NULL); - if (state) { - wl_callback_destroy(state->callback); - free(state); - } +#ifdef GLAMOR_HAS_GBM + xwl_glamor_init_gbm(xwl_screen); + if (!xwl_screen->gbm_backend.is_available && !use_eglstream) + ErrorF("xwayland glamor: GBM backend (default) is not available\n"); +#endif +#ifdef XWL_HAS_EGLSTREAM + xwl_glamor_init_eglstream(xwl_screen); + if (!xwl_screen->eglstream_backend.is_available && use_eglstream) + ErrorF("xwayland glamor: EGLStream backend requested but not available\n"); +#endif } -static void -xwl_auth_state_client_callback(CallbackListPtr *pcbl, void *unused, void *data) +static Bool +xwl_glamor_select_gbm_backend(struct xwl_screen *xwl_screen) { - NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; - ClientPtr pClient = clientinfo->client; - struct xwl_auth_state *state; - - switch (pClient->clientState) { - case ClientStateGone: - case ClientStateRetained: - state = dixLookupPrivate(&pClient->devPrivates, &xwl_auth_state_private_key); - free_xwl_auth_state(pClient, state); - break; - default: - break; +#ifdef GLAMOR_HAS_GBM + if (xwl_screen->gbm_backend.is_available && + xwl_glamor_has_wl_interfaces(xwl_screen, &xwl_screen->gbm_backend)) { + xwl_screen->egl_backend = &xwl_screen->gbm_backend; + return TRUE; } -} + else + ErrorF("Missing Wayland requirements for glamor GBM backend\n"); +#endif -static void -sync_callback(void *data, struct wl_callback *callback, uint32_t serial) -{ - struct xwl_auth_state *state = data; - ClientPtr client = state->client; - - /* if the client is gone, the callback is cancelled so it's safe to - * assume the client is still in ClientStateRunning at this point... - */ - dri3_send_open_reply(client, state->fd); - AttendClient(client); - free_xwl_auth_state(client, state); + return FALSE; } -static const struct wl_callback_listener sync_listener = { - sync_callback -}; - -static int -xwl_dri3_open_client(ClientPtr client, - ScreenPtr screen, - RRProviderPtr provider, - int *pfd) +static Bool +xwl_glamor_select_eglstream_backend(struct xwl_screen *xwl_screen) { - struct xwl_screen *xwl_screen = xwl_screen_get(screen); - struct xwl_auth_state *state; - drm_magic_t magic; - int fd; - - fd = open(xwl_screen->device_name, O_RDWR | O_CLOEXEC); - if (fd < 0) - return BadAlloc; - if (xwl_screen->fd_render_node) { - *pfd = fd; - return Success; - } - - state = malloc(sizeof *state); - if (state == NULL) { - close(fd); - return BadAlloc; +#ifdef XWL_HAS_EGLSTREAM + if (xwl_screen->eglstream_backend.is_available && + xwl_glamor_has_wl_interfaces(xwl_screen, &xwl_screen->eglstream_backend)) { + ErrorF("glamor: Using nvidia's EGLStream interface, direct rendering impossible.\n"); + ErrorF("glamor: Performance may be affected. Ask your vendor to support GBM!\n"); + xwl_screen->egl_backend = &xwl_screen->eglstream_backend; + return TRUE; } + else + ErrorF("Missing Wayland requirements for glamor EGLStream backend\n"); +#endif - state->client = client; - state->fd = fd; - - if (drmGetMagic(state->fd, &magic) < 0) { - close(state->fd); - free(state); - return BadMatch; - } - - wl_drm_authenticate(xwl_screen->drm, magic); - state->callback = wl_display_sync(xwl_screen->display); - wl_callback_add_listener(state->callback, &sync_listener, state); - dixSetPrivate(&client->devPrivates, &xwl_auth_state_private_key, state); - - IgnoreClient(client); - - return Success; + return FALSE; } -static PixmapPtr -xwl_dri3_pixmap_from_fd(ScreenPtr screen, int fd, - CARD16 width, CARD16 height, CARD16 stride, - CARD8 depth, CARD8 bpp) +void +xwl_glamor_select_backend(struct xwl_screen *xwl_screen, Bool use_eglstream) { - struct xwl_screen *xwl_screen = xwl_screen_get(screen); - struct gbm_import_fd_data data; - struct gbm_bo *bo; - PixmapPtr pixmap; - - if (width == 0 || height == 0 || - depth < 15 || bpp != BitsPerPixel(depth) || stride < width * bpp / 8) - return NULL; - - data.fd = fd; - data.width = width; - data.height = height; - data.stride = stride; - data.format = gbm_format_for_depth(depth); - bo = gbm_bo_import(xwl_screen->gbm, GBM_BO_IMPORT_FD, &data, - GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); - if (bo == NULL) - return NULL; - - pixmap = xwl_glamor_create_pixmap_for_bo(screen, bo, depth); - if (pixmap == NULL) { - gbm_bo_destroy(bo); - return NULL; + if (use_eglstream) { + if (!xwl_glamor_select_eglstream_backend(xwl_screen)) + xwl_glamor_select_gbm_backend(xwl_screen); + } + else { + if (!xwl_glamor_select_gbm_backend(xwl_screen)) + xwl_glamor_select_eglstream_backend(xwl_screen); } - - return pixmap; -} - -static int -xwl_dri3_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, - CARD16 *stride, CARD32 *size) -{ - struct xwl_pixmap *xwl_pixmap; - - xwl_pixmap = xwl_pixmap_get(pixmap); - - *stride = gbm_bo_get_stride(xwl_pixmap->bo); - *size = pixmap->drawable.width * *stride; - - return gbm_bo_get_fd(xwl_pixmap->bo); } -static dri3_screen_info_rec xwl_dri3_info = { - .version = 1, - .open = NULL, - .pixmap_from_fd = xwl_dri3_pixmap_from_fd, - .fd_from_pixmap = xwl_dri3_fd_from_pixmap, - .open_client = xwl_dri3_open_client, -}; - Bool xwl_glamor_init(struct xwl_screen *xwl_screen) { ScreenPtr screen = xwl_screen->screen; + const char *no_glamor_env; - if (xwl_screen->egl_context == EGL_NO_CONTEXT) { - ErrorF("Disabling glamor and dri3, EGL setup failed\n"); - return FALSE; - } - - if (!glamor_init(xwl_screen->screen, GLAMOR_USE_EGL_SCREEN)) { - ErrorF("Failed to initialize glamor\n"); + no_glamor_env = getenv("XWAYLAND_NO_GLAMOR"); + if (no_glamor_env && *no_glamor_env != '0') { + ErrorF("Disabling glamor and dri3 support, XWAYLAND_NO_GLAMOR is set\n"); return FALSE; } - if (!dri3_screen_init(xwl_screen->screen, &xwl_dri3_info)) { - ErrorF("Failed to initialize dri3\n"); + if (!xwl_screen->egl_backend->init_egl(xwl_screen)) { + ErrorF("EGL setup failed, disabling glamor\n"); return FALSE; } - if (!dixRegisterPrivateKey(&xwl_auth_state_private_key, PRIVATE_CLIENT, 0)) { - ErrorF("Failed to register private key\n"); + if (!glamor_init(xwl_screen->screen, GLAMOR_USE_EGL_SCREEN)) { + ErrorF("Failed to initialize glamor\n"); return FALSE; } - if (!AddCallback(&ClientStateCallback, xwl_auth_state_client_callback, NULL)) { - ErrorF("Failed to add client state callback\n"); + if (!xwl_screen->egl_backend->init_screen(xwl_screen)) { + ErrorF("EGL backend init_screen() failed, disabling glamor\n"); return FALSE; } xwl_screen->CreateScreenResources = screen->CreateScreenResources; screen->CreateScreenResources = xwl_glamor_create_screen_resources; - screen->CreatePixmap = xwl_glamor_create_pixmap; - screen->DestroyPixmap = xwl_glamor_destroy_pixmap; #ifdef XV if (!xwl_glamor_xv_init(screen)) diff --git a/xserver/hw/xwayland/xwayland-input.c b/xserver/hw/xwayland/xwayland-input.c index d96e6f2a4..fbbcb39cc 100644 --- a/xserver/hw/xwayland/xwayland-input.c +++ b/xserver/hw/xwayland/xwayland-input.c @@ -34,12 +34,14 @@ #include <inpututils.h> #include <mipointer.h> #include <mipointrst.h> +#include <misc.h> +#include "tablet-unstable-v2-client-protocol.h" -/* Copied from mipointer.c */ -#define MIPOINTER(dev) \ - (IsFloating(dev) ? \ - (miPointerPtr)dixLookupPrivate(&(dev)->devPrivates, miPointerPrivKey): \ - (miPointerPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miPointerPrivKey)) +struct axis_discrete_pending { + struct xorg_list l; + uint32_t axis; + int32_t discrete; +}; struct sync_pending { struct xorg_list l; @@ -62,6 +64,12 @@ static void xwl_seat_destroy_confined_pointer(struct xwl_seat *xwl_seat); static void +init_tablet_manager_seat(struct xwl_screen *xwl_screen, + struct xwl_seat *xwl_seat); +static void +release_tablet_manager_seat(struct xwl_seat *xwl_seat); + +static void xwl_pointer_control(DeviceIntPtr device, PtrCtrl *ctrl) { /* Nothing to do, dix handles all settings */ @@ -287,6 +295,75 @@ xwl_touch_proc(DeviceIntPtr device, int what) #undef NTOUCHPOINTS } +static int +xwl_tablet_proc(DeviceIntPtr device, int what) +{ +#define NBUTTONS 9 +#define NAXES 6 + Atom btn_labels[NBUTTONS] = { 0 }; + Atom axes_labels[NAXES] = { 0 }; + BYTE map[NBUTTONS + 1] = { 0 }; + int i; + + switch (what) { + case DEVICE_INIT: + device->public.on = FALSE; + + for (i = 1; i <= NBUTTONS; i++) + map[i] = i; + + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y); + axes_labels[2] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_PRESSURE); + axes_labels[3] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_TILT_X); + axes_labels[4] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_TILT_Y); + axes_labels[5] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_WHEEL); + + if (!InitValuatorClassDeviceStruct(device, NAXES, axes_labels, + GetMotionHistorySize(), Absolute)) + return BadValue; + + /* Valuators - match the xf86-input-wacom ranges */ + InitValuatorAxisStruct(device, 0, axes_labels[0], + 0, 262143, 10000, 0, 10000, Absolute); + InitValuatorAxisStruct(device, 1, axes_labels[1], + 0, 262143, 10000, 0, 10000, Absolute); + /* pressure */ + InitValuatorAxisStruct(device, 2, axes_labels[2], + 0, 65535, 1, 0, 1, Absolute); + /* tilt x */ + InitValuatorAxisStruct(device, 3, axes_labels[3], + -64, 63, 57, 0, 57, Absolute); + /* tilt y */ + InitValuatorAxisStruct(device, 4, axes_labels[4], + -64, 63, 57, 0, 57, Absolute); + /* abs wheel (airbrush) or rotation (artpen) */ + InitValuatorAxisStruct(device, 5, axes_labels[5], + -900, 899, 1, 0, 1, Absolute); + + if (!InitPtrFeedbackClassDeviceStruct(device, xwl_pointer_control)) + return BadValue; + + if (!InitButtonClassDeviceStruct(device, NBUTTONS, btn_labels, map)) + return BadValue; + + return Success; + + case DEVICE_ON: + device->public.on = TRUE; + return Success; + + case DEVICE_OFF: + case DEVICE_CLOSE: + device->public.on = FALSE; + return Success; + } + + return BadMatch; +#undef NAXES +#undef NBUTTONS +} + static void pointer_handle_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, @@ -347,9 +424,9 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer, * of our surfaces might not have been shown. In that case we'll * have a cursor surface frame callback pending which we need to * clear so that we can continue submitting new cursor frames. */ - if (xwl_seat->cursor_frame_cb) { - wl_callback_destroy(xwl_seat->cursor_frame_cb); - xwl_seat->cursor_frame_cb = NULL; + if (xwl_seat->cursor.frame_cb) { + wl_callback_destroy(xwl_seat->cursor.frame_cb); + xwl_seat->cursor.frame_cb = NULL; xwl_seat_set_cursor(xwl_seat); } @@ -494,6 +571,8 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer, int index; const int divisor = 10; ValuatorMask mask; + struct axis_discrete_pending *pending = NULL; + struct axis_discrete_pending *iter; switch (axis) { case WL_POINTER_AXIS_VERTICAL_SCROLL: @@ -506,8 +585,22 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer, return; } + xorg_list_for_each_entry(iter, &xwl_seat->axis_discrete_pending, l) { + if (iter->axis == axis) { + pending = iter; + break; + } + } + valuator_mask_zero(&mask); - valuator_mask_set_double(&mask, index, wl_fixed_to_double(value) / divisor); + + if (pending) { + valuator_mask_set(&mask, index, pending->discrete); + xorg_list_del(&pending->l); + free(pending); + } else { + valuator_mask_set_double(&mask, index, wl_fixed_to_double(value) / divisor); + } QueuePointerEvents(xwl_seat->pointer, MotionNotify, 0, POINTER_RELATIVE, &mask); } @@ -537,6 +630,16 @@ static void pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) { + struct xwl_seat *xwl_seat = data; + + struct axis_discrete_pending *pending = malloc(sizeof *pending); + if (!pending) + return; + + pending->axis = axis; + pending->discrete = discrete; + + xorg_list_add(&pending->l, &xwl_seat->axis_discrete_pending); } static const struct wl_pointer_listener pointer_listener = { @@ -864,9 +967,9 @@ touch_handle_down(void *data, struct wl_touch *wl_touch, if (surface == NULL) return; - xwl_touch = calloc(sizeof *xwl_touch, 1); + xwl_touch = calloc(1, sizeof *xwl_touch); if (xwl_touch == NULL) { - ErrorF("touch_handle_down ENOMEM"); + ErrorF("%s: ENOMEM\n", __func__); return; } @@ -945,6 +1048,84 @@ static const struct wl_touch_listener touch_listener = { touch_handle_cancel }; +static struct xwl_seat * +find_matching_seat(DeviceIntPtr device) +{ + DeviceIntPtr dev; + + for (dev = inputInfo.devices; dev; dev = dev->next) + if (dev->deviceProc == xwl_keyboard_proc && + device == GetMaster(dev, MASTER_KEYBOARD)) + return (struct xwl_seat *) dev->public.devicePrivate; + + return NULL; +} + +static void +release_grab(struct xwl_seat *xwl_seat) +{ + if (xwl_seat->keyboard_grab) + zwp_xwayland_keyboard_grab_v1_destroy(xwl_seat->keyboard_grab); + xwl_seat->keyboard_grab = NULL; +} + +static void +set_grab(struct xwl_seat *xwl_seat, struct xwl_window *xwl_window) +{ + struct xwl_screen *xwl_screen; + + if (!xwl_window) + return; + + /* We already have a grab */ + if (xwl_seat->keyboard_grab) + release_grab (xwl_seat); + + xwl_screen = xwl_seat->xwl_screen; + xwl_seat->keyboard_grab = + zwp_xwayland_keyboard_grab_manager_v1_grab_keyboard(xwl_screen->wp_grab, + xwl_window->surface, + xwl_seat->seat); +} + +static void +xwl_keyboard_activate_grab(DeviceIntPtr device, GrabPtr grab, TimeStamp time, Bool passive) +{ + struct xwl_seat *xwl_seat = device->public.devicePrivate; + + /* We are not interested in passive grabs */ + if (!passive) { + /* If the device is the MASTER_KEYBOARD, we don't have an xwl_seat */ + if (xwl_seat == NULL) + xwl_seat = find_matching_seat(device); + if (xwl_seat) + set_grab(xwl_seat, xwl_window_from_window(grab->window)); + } + + ActivateKeyboardGrab(device, grab, time, passive); +} + +static void +xwl_keyboard_deactivate_grab(DeviceIntPtr device) +{ + struct xwl_seat *xwl_seat = device->public.devicePrivate; + + /* If the device is the MASTER_KEYBOARD, we don't have an xwl_seat */ + if (xwl_seat == NULL) + xwl_seat = find_matching_seat(device); + if (xwl_seat) + release_grab (xwl_seat); + + DeactivateKeyboardGrab(device); +} + +static void +setup_keyboard_grab_handler (DeviceIntPtr device) +{ + device->deviceGrab.ActivateGrab = xwl_keyboard_activate_grab; + device->deviceGrab.DeactivateGrab = xwl_keyboard_deactivate_grab; +} + static DeviceIntPtr add_device(struct xwl_seat *xwl_seat, const char *driver, DeviceProc device_proc) @@ -1033,6 +1214,8 @@ release_relative_pointer(struct xwl_seat *xwl_seat) static void init_keyboard(struct xwl_seat *xwl_seat) { + DeviceIntPtr master; + xwl_seat->wl_keyboard = wl_seat_get_keyboard(xwl_seat->seat); wl_keyboard_add_listener(xwl_seat->wl_keyboard, &keyboard_listener, xwl_seat); @@ -1044,11 +1227,19 @@ init_keyboard(struct xwl_seat *xwl_seat) } EnableDevice(xwl_seat->keyboard, TRUE); xwl_seat->keyboard->key->xkbInfo->checkRepeat = keyboard_check_repeat; + + if (xwl_seat->xwl_screen->wp_grab) { + /* We have Xwayland grab protocol supported by the compositor */ + master = GetMaster(xwl_seat->keyboard, MASTER_KEYBOARD); + if (master) + setup_keyboard_grab_handler(master); + } } static void release_keyboard(struct xwl_seat *xwl_seat) { + release_grab(xwl_seat); wl_keyboard_release(xwl_seat->wl_keyboard); xwl_seat->wl_keyboard = NULL; @@ -1126,13 +1317,38 @@ static const struct wl_seat_listener seat_listener = { }; static void +xwl_cursor_init(struct xwl_cursor *xwl_cursor, struct xwl_screen *xwl_screen, + void (* update_proc)(struct xwl_cursor *)) +{ + xwl_cursor->surface = wl_compositor_create_surface(xwl_screen->compositor); + xwl_cursor->update_proc = update_proc; + xwl_cursor->frame_cb = NULL; + xwl_cursor->needs_update = FALSE; +} + +static void +xwl_cursor_release(struct xwl_cursor *xwl_cursor) +{ + wl_surface_destroy(xwl_cursor->surface); + if (xwl_cursor->frame_cb) + wl_callback_destroy(xwl_cursor->frame_cb); +} + +static void +xwl_seat_update_cursor(struct xwl_cursor *xwl_cursor) +{ + struct xwl_seat *xwl_seat = wl_container_of(xwl_cursor, xwl_seat, cursor); + xwl_seat_set_cursor(xwl_seat); +} + +static void create_input_device(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version) { struct xwl_seat *xwl_seat; - xwl_seat = calloc(sizeof *xwl_seat, 1); + xwl_seat = calloc(1, sizeof *xwl_seat); if (xwl_seat == NULL) { - ErrorF("create_input ENOMEM\n"); + ErrorF("%s: ENOMEM\n", __func__); return; } @@ -1144,11 +1360,16 @@ create_input_device(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version &wl_seat_interface, min(version, 5)); xwl_seat->id = id; - xwl_seat->cursor = wl_compositor_create_surface(xwl_screen->compositor); + xwl_cursor_init(&xwl_seat->cursor, xwl_seat->xwl_screen, + xwl_seat_update_cursor); wl_seat_add_listener(xwl_seat->seat, &seat_listener, xwl_seat); + + init_tablet_manager_seat(xwl_screen, xwl_seat); + wl_array_init(&xwl_seat->keys); xorg_list_init(&xwl_seat->touches); + xorg_list_init(&xwl_seat->axis_discrete_pending); xorg_list_init(&xwl_seat->sync_pending); } @@ -1157,6 +1378,7 @@ xwl_seat_destroy(struct xwl_seat *xwl_seat) { struct xwl_touch *xwl_touch, *next_xwl_touch; struct sync_pending *p, *npd; + struct axis_discrete_pending *ad, *ad_next; xorg_list_for_each_entry_safe(xwl_touch, next_xwl_touch, &xwl_seat->touches, link_touch) { @@ -1169,15 +1391,1035 @@ xwl_seat_destroy(struct xwl_seat *xwl_seat) free (p); } + xorg_list_for_each_entry_safe(ad, ad_next, &xwl_seat->axis_discrete_pending, l) { + xorg_list_del(&ad->l); + free(ad); + } + + release_tablet_manager_seat(xwl_seat); + + release_grab(xwl_seat); wl_seat_destroy(xwl_seat->seat); - wl_surface_destroy(xwl_seat->cursor); - if (xwl_seat->cursor_frame_cb) - wl_callback_destroy(xwl_seat->cursor_frame_cb); + xwl_cursor_release(&xwl_seat->cursor); wl_array_release(&xwl_seat->keys); free(xwl_seat); } static void +tablet_handle_name(void *data, struct zwp_tablet_v2 *tablet, const char *name) +{ +} + +static void +tablet_handle_id(void *data, struct zwp_tablet_v2 *tablet, uint32_t vid, + uint32_t pid) +{ +} + +static void +tablet_handle_path(void *data, struct zwp_tablet_v2 *tablet, const char *path) +{ +} + +static void +tablet_handle_done(void *data, struct zwp_tablet_v2 *tablet) +{ + struct xwl_tablet *xwl_tablet = data; + struct xwl_seat *xwl_seat = xwl_tablet->seat; + + if (xwl_seat->stylus == NULL) { + xwl_seat->stylus = add_device(xwl_seat, "xwayland-stylus", xwl_tablet_proc); + ActivateDevice(xwl_seat->stylus, TRUE); + } + EnableDevice(xwl_seat->stylus, TRUE); + + if (xwl_seat->eraser == NULL) { + xwl_seat->eraser = add_device(xwl_seat, "xwayland-eraser", xwl_tablet_proc); + ActivateDevice(xwl_seat->eraser, TRUE); + } + EnableDevice(xwl_seat->eraser, TRUE); + + if (xwl_seat->puck == NULL) { + xwl_seat->puck = add_device(xwl_seat, "xwayland-cursor", xwl_tablet_proc); + ActivateDevice(xwl_seat->puck, TRUE); + } + EnableDevice(xwl_seat->puck, TRUE); +} + +static void +tablet_handle_removed(void *data, struct zwp_tablet_v2 *tablet) +{ + struct xwl_tablet *xwl_tablet = data; + struct xwl_seat *xwl_seat = xwl_tablet->seat; + + xorg_list_del(&xwl_tablet->link); + + /* The tablet is merely disabled, not removed. The next tablet + will re-use the same X devices */ + if (xorg_list_is_empty(&xwl_seat->tablets)) { + if (xwl_seat->stylus) + DisableDevice(xwl_seat->stylus, TRUE); + if (xwl_seat->eraser) + DisableDevice(xwl_seat->eraser, TRUE); + if (xwl_seat->puck) + DisableDevice(xwl_seat->puck, TRUE); + /* pads are removed separately */ + } + + zwp_tablet_v2_destroy(tablet); + free(xwl_tablet); +} + +static const struct zwp_tablet_v2_listener tablet_listener = { + tablet_handle_name, + tablet_handle_id, + tablet_handle_path, + tablet_handle_done, + tablet_handle_removed +}; + +static void +tablet_tool_receive_type(void *data, struct zwp_tablet_tool_v2 *tool, + uint32_t type) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + + switch (type) { + case ZWP_TABLET_TOOL_V2_TYPE_ERASER: + xwl_tablet_tool->xdevice = xwl_seat->eraser; + break; + case ZWP_TABLET_TOOL_V2_TYPE_MOUSE: + case ZWP_TABLET_TOOL_V2_TYPE_LENS: + xwl_tablet_tool->xdevice = xwl_seat->puck; + break; + default: + xwl_tablet_tool->xdevice = xwl_seat->stylus; + break; + } +} + +static void +tablet_tool_receive_hardware_serial(void *data, struct zwp_tablet_tool_v2 *tool, + uint32_t hi, uint32_t low) +{ +} + +static void +tablet_tool_receive_hardware_id_wacom(void *data, struct zwp_tablet_tool_v2 *tool, + uint32_t hi, uint32_t low) +{ +} + +static void +tablet_tool_receive_capability(void *data, struct zwp_tablet_tool_v2 *tool, + uint32_t capability) +{ +} + +static void +tablet_tool_receive_done(void *data, struct zwp_tablet_tool_v2 *tool) +{ +} + +static void +tablet_tool_receive_removed(void *data, struct zwp_tablet_tool_v2 *tool) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + + xorg_list_del(&xwl_tablet_tool->link); + xwl_cursor_release(&xwl_tablet_tool->cursor); + zwp_tablet_tool_v2_destroy(tool); + free(xwl_tablet_tool); +} + +static void +tablet_tool_proximity_in(void *data, struct zwp_tablet_tool_v2 *tool, + uint32_t serial, struct zwp_tablet_v2 *tablet, + struct wl_surface *wl_surface) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + + /* There's a race here where if we create and then immediately + * destroy a surface, we might end up in a state where the Wayland + * compositor sends us an event for a surface that doesn't exist. + * + * Don't process enter events in this case. + * + * see pointer_handle_enter() + */ + if (wl_surface == NULL) + return; + + xwl_tablet_tool->proximity_in_serial = serial; + xwl_seat->tablet_focus_window = wl_surface_get_user_data(wl_surface); + + xwl_tablet_tool_set_cursor(xwl_tablet_tool); +} + +static void +tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *tool) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + + xwl_tablet_tool->proximity_in_serial = 0; + xwl_seat->tablet_focus_window = NULL; + + xwl_tablet_tool->pressure = 0; + xwl_tablet_tool->tilt_x = 0; + xwl_tablet_tool->tilt_y = 0; + xwl_tablet_tool->rotation = 0; + xwl_tablet_tool->slider = 0; +} + +static void +tablet_tool_down(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t serial) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + ValuatorMask mask; + + xwl_seat->xwl_screen->serial = serial; + + valuator_mask_zero(&mask); + QueuePointerEvents(xwl_tablet_tool->xdevice, ButtonPress, 1, 0, &mask); +} + +static void +tablet_tool_up(void *data, struct zwp_tablet_tool_v2 *tool) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + ValuatorMask mask; + + valuator_mask_zero(&mask); + QueuePointerEvents(xwl_tablet_tool->xdevice, ButtonRelease, 1, 0, &mask); +} + +static void +tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool, + wl_fixed_t x, wl_fixed_t y) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + int32_t dx, dy; + double sx = wl_fixed_to_double(x); + double sy = wl_fixed_to_double(y); + + if (!xwl_seat->tablet_focus_window) + return; + + dx = xwl_seat->tablet_focus_window->window->drawable.x; + dy = xwl_seat->tablet_focus_window->window->drawable.y; + + xwl_tablet_tool->x = (double) dx + sx; + xwl_tablet_tool->y = (double) dy + sy; +} + +static void +tablet_tool_pressure(void *data, struct zwp_tablet_tool_v2 *tool, + uint32_t pressure) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + + if (!xwl_seat->tablet_focus_window) + return; + + /* normalized to 65535 already */ + xwl_tablet_tool->pressure = pressure; +} + +static void +tablet_tool_distance(void *data, struct zwp_tablet_tool_v2 *tool, + uint32_t distance_raw) +{ +} + +static void +tablet_tool_tilt(void *data, struct zwp_tablet_tool_v2 *tool, + wl_fixed_t tilt_x, wl_fixed_t tilt_y) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + + if (!xwl_seat->tablet_focus_window) + return; + + xwl_tablet_tool->tilt_x = wl_fixed_to_double(tilt_x); + xwl_tablet_tool->tilt_y = wl_fixed_to_double(tilt_y); +} + +static void +tablet_tool_rotation(void *data, struct zwp_tablet_tool_v2 *tool, + wl_fixed_t angle) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + double rotation = wl_fixed_to_double(angle); + + if (!xwl_seat->tablet_focus_window) + return; + + /* change origin (buttons facing right [libinput +90 degrees]) and + * scaling (5 points per degree) to match wacom driver behavior + */ + rotation = remainderf(rotation + 90.0f, 360.0f); + rotation *= 5.0f; + xwl_tablet_tool->rotation = rotation; +} + +static void +tablet_tool_slider(void *data, struct zwp_tablet_tool_v2 *tool, + int32_t position_raw) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + float position = position_raw / 65535.0; + + if (!xwl_seat->tablet_focus_window) + return; + + xwl_tablet_tool->slider = (position * 1799.0f) - 900.0f; +} + +static void +tablet_tool_wheel(void *data, struct zwp_tablet_tool_v2 *tool, + wl_fixed_t degrees, int32_t clicks) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + + if (!xwl_seat->tablet_focus_window) + return; + + xwl_tablet_tool->wheel_clicks = clicks; +} + +static void +tablet_tool_button_state(void *data, struct zwp_tablet_tool_v2 *tool, + uint32_t serial, uint32_t button, uint32_t state) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + uint32_t *mask = &xwl_tablet_tool->buttons_now; + int xbtn = 0; + + /* BTN_0 .. BTN_9 */ + if (button >= 0x100 && button <= 0x109) { + xbtn = button - 0x100 + 1; + } + /* BTN_A .. BTN_Z */ + else if (button >= 0x130 && button <= 0x135) { + xbtn = button - 0x130 + 10; + } + /* BTN_BASE .. BTN_BASE6 */ + else if (button >= 0x126 && button <= 0x12b) { + xbtn = button - 0x126 + 16; + } + else { + switch (button) { + case 0x110: /* BTN_LEFT */ + case 0x14a: /* BTN_TOUCH */ + xbtn = 1; + break; + + case 0x112: /* BTN_MIDDLE */ + case 0x14b: /* BTN_STYLUS */ + xbtn = 2; + break; + + case 0x111: /* BTN_RIGHT */ + case 0x14c: /* BTN_STYLUS2 */ + xbtn = 3; + break; + + case 0x113: /* BTN_SIDE */ + case 0x116: /* BTN_BACK */ + case 0x149: /* BTN_STYLUS3 */ + xbtn = 8; + break; + + case 0x114: /* BTN_EXTRA */ + case 0x115: /* BTN_FORWARD */ + xbtn = 9; + break; + } + } + + if (!xbtn) { + ErrorF("unknown tablet button number %d\n", button); + return; + } + + BUG_RETURN(xbtn >= 8 * sizeof(*mask)); + + if (state) + SetBit(mask, xbtn - 1); + else + ClearBit(mask, xbtn - 1); + + xwl_seat->xwl_screen->serial = serial; +} + +static void +tablet_tool_frame(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t time) +{ + struct xwl_tablet_tool *xwl_tablet_tool = data; + ValuatorMask mask; + uint32_t released, pressed, diff; + int button; + + valuator_mask_zero(&mask); + valuator_mask_set_double(&mask, 0, xwl_tablet_tool->x); + valuator_mask_set_double(&mask, 1, xwl_tablet_tool->y); + valuator_mask_set(&mask, 2, xwl_tablet_tool->pressure); + valuator_mask_set_double(&mask, 3, xwl_tablet_tool->tilt_x); + valuator_mask_set_double(&mask, 4, xwl_tablet_tool->tilt_y); + valuator_mask_set_double(&mask, 5, xwl_tablet_tool->rotation + xwl_tablet_tool->slider); + + QueuePointerEvents(xwl_tablet_tool->xdevice, MotionNotify, 0, + POINTER_ABSOLUTE | POINTER_DESKTOP, &mask); + + valuator_mask_zero(&mask); + + diff = xwl_tablet_tool->buttons_prev ^ xwl_tablet_tool->buttons_now; + released = diff & ~xwl_tablet_tool->buttons_now; + pressed = diff & xwl_tablet_tool->buttons_now; + + button = 1; + while (released) { + if (released & 0x1) + QueuePointerEvents(xwl_tablet_tool->xdevice, + ButtonRelease, button, 0, &mask); + button++; + released >>= 1; + } + + button = 1; + while (pressed) { + if (pressed & 0x1) + QueuePointerEvents(xwl_tablet_tool->xdevice, + ButtonPress, button, 0, &mask); + button++; + pressed >>= 1; + } + + xwl_tablet_tool->buttons_prev = xwl_tablet_tool->buttons_now; + + while (xwl_tablet_tool->wheel_clicks) { + if (xwl_tablet_tool->wheel_clicks < 0) { + button = 4; + xwl_tablet_tool->wheel_clicks++; + } + else { + button = 5; + xwl_tablet_tool->wheel_clicks--; + } + + QueuePointerEvents(xwl_tablet_tool->xdevice, + ButtonPress, button, 0, &mask); + QueuePointerEvents(xwl_tablet_tool->xdevice, + ButtonRelease, button, 0, &mask); + + } +} + +static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = { + tablet_tool_receive_type, + tablet_tool_receive_hardware_serial, + tablet_tool_receive_hardware_id_wacom, + tablet_tool_receive_capability, + tablet_tool_receive_done, + tablet_tool_receive_removed, + tablet_tool_proximity_in, + tablet_tool_proximity_out, + tablet_tool_down, + tablet_tool_up, + tablet_tool_motion, + tablet_tool_pressure, + tablet_tool_distance, + tablet_tool_tilt, + tablet_tool_rotation, + tablet_tool_slider, + tablet_tool_wheel, + tablet_tool_button_state, + tablet_tool_frame +}; + +static void +tablet_pad_ring_destroy(struct xwl_tablet_pad_ring *ring) +{ + zwp_tablet_pad_ring_v2_destroy(ring->ring); + xorg_list_del(&ring->link); + free(ring); +} + +static void +tablet_pad_ring_source(void *data, + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, + uint32_t source) +{ +} + +static void +tablet_pad_ring_angle(void *data, + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, + wl_fixed_t degrees) +{ + struct xwl_tablet_pad_ring *ring = data; + struct xwl_tablet_pad *pad = ring->group->pad; + double deg = wl_fixed_to_double(degrees); + ValuatorMask mask; + + valuator_mask_zero(&mask); + valuator_mask_set(&mask, 5 + ring->index, deg/360.0 * 71); + QueuePointerEvents(pad->xdevice, MotionNotify, 0, 0, &mask); +} + +static void +tablet_pad_ring_stop(void *data, + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2) +{ +} + +static void +tablet_pad_ring_frame(void *data, + struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, + uint32_t time) +{ +} + +static const struct zwp_tablet_pad_ring_v2_listener tablet_pad_ring_listener = { + tablet_pad_ring_source, + tablet_pad_ring_angle, + tablet_pad_ring_stop, + tablet_pad_ring_frame, +}; + + +static void +tablet_pad_strip_destroy(struct xwl_tablet_pad_strip *strip) +{ + zwp_tablet_pad_strip_v2_destroy(strip->strip); + xorg_list_del(&strip->link); + free(strip); +} + +static void +tablet_pad_strip_source(void *data, + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, + uint32_t source) +{ +} + +static void +tablet_pad_strip_position(void *data, + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, + uint32_t position) +{ + struct xwl_tablet_pad_strip *strip = data; + struct xwl_tablet_pad *pad = strip->group->pad; + ValuatorMask mask; + + valuator_mask_zero(&mask); + valuator_mask_set(&mask, 3 + strip->index, position/65535.0 * 2048); + QueuePointerEvents(pad->xdevice, MotionNotify, 0, 0, &mask); +} + +static void +tablet_pad_strip_stop(void *data, + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2) +{ +} + +static void +tablet_pad_strip_frame(void *data, + struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, + uint32_t time) +{ +} + +static const struct zwp_tablet_pad_strip_v2_listener tablet_pad_strip_listener = { + tablet_pad_strip_source, + tablet_pad_strip_position, + tablet_pad_strip_stop, + tablet_pad_strip_frame, +}; + +static void +tablet_pad_group_destroy(struct xwl_tablet_pad_group *group) +{ + struct xwl_tablet_pad_ring *r, *tr; + struct xwl_tablet_pad_strip *s, *ts; + + xorg_list_for_each_entry_safe(r, tr, + &group->pad_group_ring_list, + link) + tablet_pad_ring_destroy(r); + + xorg_list_for_each_entry_safe(s, ts, + &group->pad_group_strip_list, + link) + tablet_pad_strip_destroy(s); + + zwp_tablet_pad_group_v2_destroy(group->group); + xorg_list_del(&group->link); + free(group); +} + +static void +tablet_pad_group_buttons(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + struct wl_array *buttons) +{ + +} + +static void +tablet_pad_group_ring(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + struct zwp_tablet_pad_ring_v2 *wp_ring) +{ + static unsigned int ring_index = 0; + struct xwl_tablet_pad_group *group = data; + struct xwl_tablet_pad_ring *ring; + + ring = calloc(1, sizeof *ring); + if (ring == NULL) { + ErrorF("%s ENOMEM\n", __func__); + return; + } + + ring->index = ring_index++; + ring->group = group; + ring->ring = wp_ring; + + xorg_list_add(&ring->link, &group->pad_group_ring_list); + + zwp_tablet_pad_ring_v2_add_listener(wp_ring, &tablet_pad_ring_listener, + ring); +} + +static void +tablet_pad_group_strip(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + struct zwp_tablet_pad_strip_v2 *wp_strip) +{ + static unsigned int strip_index = 0; + struct xwl_tablet_pad_group *group = data; + struct xwl_tablet_pad_strip *strip; + + strip = calloc(1, sizeof *strip); + if (strip == NULL) { + ErrorF("%s ENOMEM\n", __func__); + return; + } + + strip->index = strip_index++; + strip->group = group; + strip->strip = wp_strip; + + xorg_list_add(&strip->link, &group->pad_group_strip_list); + + zwp_tablet_pad_strip_v2_add_listener(wp_strip, &tablet_pad_strip_listener, + strip); +} + +static void +tablet_pad_group_modes(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + uint32_t modes) +{ + +} + +static void +tablet_pad_group_done(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2) +{ + +} + +static void +tablet_pad_group_mode_switch(void *data, + struct zwp_tablet_pad_group_v2 *zwp_tablet_pad_group_v2, + uint32_t time, + uint32_t serial, + uint32_t mode) +{ + +} + +static struct zwp_tablet_pad_group_v2_listener tablet_pad_group_listener = { + tablet_pad_group_buttons, + tablet_pad_group_ring, + tablet_pad_group_strip, + tablet_pad_group_modes, + tablet_pad_group_done, + tablet_pad_group_mode_switch, +}; + +static int +xwl_tablet_pad_proc(DeviceIntPtr device, int what) +{ + struct xwl_tablet_pad *pad = device->public.devicePrivate; + /* Axis layout mirrors that of xf86-input-wacom to have better + compatibility with existing clients */ +#define NAXES 7 + Atom axes_labels[NAXES] = { 0 }; + BYTE map[MAX_BUTTONS + 1]; + int i = 0; + Atom btn_labels[MAX_BUTTONS] = { 0 }; /* btn labels are meaningless */ + int nbuttons; + + switch (what) { + case DEVICE_INIT: + device->public.on = FALSE; + + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y); + /* The others have no good mapping */ + + if (!InitValuatorClassDeviceStruct(device, NAXES, axes_labels, + GetMotionHistorySize(), Absolute)) + return BadValue; + + for (i = 1; i <= MAX_BUTTONS; i++) + map[i] = i; + + /* We need at least 7 buttons to allow scrolling */ + nbuttons = min(max(pad->nbuttons + 4, 7), MAX_BUTTONS); + + if (!InitButtonClassDeviceStruct(device, nbuttons, + btn_labels, map)) + return BadValue; + + /* Valuators */ + InitValuatorAxisStruct(device, 0, axes_labels[0], + 0, 100, 1, 0, 1, Absolute); + InitValuatorAxisStruct(device, 1, axes_labels[1], + 0, 100, 1, 0, 1, Absolute); + /* Pressure - unused, for backwards compat only */ + InitValuatorAxisStruct(device, 2, axes_labels[2], + 0, 2048, 1, 0, 1, Absolute); + /* strip x */ + InitValuatorAxisStruct(device, 3, axes_labels[3], + 0, 2048, 1, 0, 1, Absolute); + /* strip y */ + InitValuatorAxisStruct(device, 4, axes_labels[4], + 0, 2048, 1, 0, 1, Absolute); + /* ring */ + InitValuatorAxisStruct(device, 5, axes_labels[5], + 0, 71, 1, 0, 1, Absolute); + /* ring2 */ + InitValuatorAxisStruct(device, 6, axes_labels[6], + 0, 71, 1, 0, 1, Absolute); + + if (!InitPtrFeedbackClassDeviceStruct(device, xwl_pointer_control)) + return BadValue; + + return Success; + + case DEVICE_ON: + device->public.on = TRUE; + return Success; + + case DEVICE_OFF: + case DEVICE_CLOSE: + device->public.on = FALSE; + return Success; + } + + return BadMatch; +#undef NAXES +} + +static void +tablet_pad_group(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + struct zwp_tablet_pad_group_v2 *pad_group) +{ + struct xwl_tablet_pad *pad = data; + struct xwl_tablet_pad_group *group; + + group = calloc(1, sizeof *group); + if (pad == NULL) { + ErrorF("%s ENOMEM\n", __func__); + return; + } + + group->pad = pad; + group->group = pad_group; + xorg_list_init(&group->pad_group_ring_list); + xorg_list_init(&group->pad_group_strip_list); + + xorg_list_add(&group->link, &pad->pad_group_list); + + zwp_tablet_pad_group_v2_add_listener(pad_group, + &tablet_pad_group_listener, + group); +} + +static void +tablet_pad_path(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + const char *path) +{ + +} + +static void +tablet_pad_buttons(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + uint32_t buttons) +{ + struct xwl_tablet_pad *pad = data; + + pad->nbuttons = buttons; +} + +static void +tablet_pad_done(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) +{ + struct xwl_tablet_pad *pad = data; + + pad->xdevice = add_device(pad->seat, "xwayland-pad", + xwl_tablet_pad_proc); + pad->xdevice->public.devicePrivate = pad; + ActivateDevice(pad->xdevice, TRUE); + EnableDevice(pad->xdevice, TRUE); +} + +static void +tablet_pad_button(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + uint32_t time, + uint32_t button, + uint32_t state) +{ + struct xwl_tablet_pad *pad = data; + ValuatorMask mask; + + button++; /* wayland index vs X's 1-offset */ + /* skip scroll wheel buttons 4-7 */ + button = button > 3 ? button + 4 : button; + + valuator_mask_zero(&mask); + QueuePointerEvents(pad->xdevice, + state ? ButtonPress : ButtonRelease, button, 0, &mask); +} + +static void +tablet_pad_enter(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + uint32_t serial, + struct zwp_tablet_v2 *tablet, + struct wl_surface *surface) +{ + /* pairs the pad with the tablet but also to set the focus. We + * don't care about the pairing and always use X's focus */ +} + +static void +tablet_pad_leave(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, + uint32_t serial, + struct wl_surface *surface) +{ + /* pairs the pad with the tablet but also to set the focus. We + * don't care about the pairing and always use X's focus */ +} + +static void +tablet_pad_removed(void *data, + struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) +{ + struct xwl_tablet_pad *pad = data; + struct xwl_tablet_pad_group *g, *tg; + + xorg_list_for_each_entry_safe(g, tg, &pad->pad_group_list, link) + tablet_pad_group_destroy(g); + + RemoveDevice(pad->xdevice, TRUE); + xorg_list_del(&pad->link); + zwp_tablet_pad_v2_destroy(pad->pad); + free(pad); +} + +static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = { + tablet_pad_group, + tablet_pad_path, + tablet_pad_buttons, + tablet_pad_done, + tablet_pad_button, + tablet_pad_enter, + tablet_pad_leave, + tablet_pad_removed, +}; + +static void +tablet_seat_handle_add_tablet(void *data, struct zwp_tablet_seat_v2 *tablet_seat, + struct zwp_tablet_v2 *tablet) +{ + struct xwl_seat *xwl_seat = data; + struct xwl_tablet *xwl_tablet; + + xwl_tablet = calloc(sizeof *xwl_tablet, 1); + if (xwl_tablet == NULL) { + ErrorF("%s ENOMEM\n", __func__); + return; + } + + xwl_tablet->tablet = tablet; + xwl_tablet->seat = xwl_seat; + + xorg_list_add(&xwl_tablet->link, &xwl_seat->tablets); + + zwp_tablet_v2_add_listener(tablet, &tablet_listener, xwl_tablet); +} + +static void +xwl_tablet_tool_update_cursor(struct xwl_cursor *xwl_cursor) +{ + struct xwl_tablet_tool *xwl_tablet_tool = wl_container_of(xwl_cursor, + xwl_tablet_tool, + cursor); + xwl_tablet_tool_set_cursor(xwl_tablet_tool); +} + +static void +tablet_seat_handle_add_tool(void *data, struct zwp_tablet_seat_v2 *tablet_seat, + struct zwp_tablet_tool_v2 *tool) +{ + struct xwl_seat *xwl_seat = data; + struct xwl_screen *xwl_screen = xwl_seat->xwl_screen; + struct xwl_tablet_tool *xwl_tablet_tool; + + xwl_tablet_tool = calloc(sizeof *xwl_tablet_tool, 1); + if (xwl_tablet_tool == NULL) { + ErrorF("%s ENOMEM\n", __func__); + return; + } + + xwl_tablet_tool->tool = tool; + xwl_tablet_tool->seat = xwl_seat; + xwl_cursor_init(&xwl_tablet_tool->cursor, xwl_screen, + xwl_tablet_tool_update_cursor); + + xorg_list_add(&xwl_tablet_tool->link, &xwl_seat->tablet_tools); + + zwp_tablet_tool_v2_add_listener(tool, &tablet_tool_listener, xwl_tablet_tool); +} + +static void +tablet_seat_handle_add_pad(void *data, struct zwp_tablet_seat_v2 *tablet_seat, + struct zwp_tablet_pad_v2 *pad) +{ + struct xwl_seat *xwl_seat = data; + struct xwl_tablet_pad *xwl_tablet_pad; + + xwl_tablet_pad = calloc(sizeof *xwl_tablet_pad, 1); + if (xwl_tablet_pad == NULL) { + ErrorF("%s ENOMEM\n", __func__); + return; + } + + xwl_tablet_pad->pad = pad; + xwl_tablet_pad->seat = xwl_seat; + xorg_list_init(&xwl_tablet_pad->pad_group_list); + + xorg_list_add(&xwl_tablet_pad->link, &xwl_seat->tablet_pads); + + zwp_tablet_pad_v2_add_listener(pad, &tablet_pad_listener, + xwl_tablet_pad); +} + +static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = { + tablet_seat_handle_add_tablet, + tablet_seat_handle_add_tool, + tablet_seat_handle_add_pad +}; + +static void +init_tablet_manager_seat(struct xwl_screen *xwl_screen, + struct xwl_seat *xwl_seat) +{ + xorg_list_init(&xwl_seat->tablets); + xorg_list_init(&xwl_seat->tablet_tools); + xorg_list_init(&xwl_seat->tablet_pads); + + if (!xwl_screen->tablet_manager) + return; + + xwl_seat->tablet_seat = + zwp_tablet_manager_v2_get_tablet_seat(xwl_screen->tablet_manager, + xwl_seat->seat); + + zwp_tablet_seat_v2_add_listener(xwl_seat->tablet_seat, &tablet_seat_listener, xwl_seat); +} + +static void +release_tablet_manager_seat(struct xwl_seat *xwl_seat) +{ + struct xwl_tablet *xwl_tablet, *next_xwl_tablet; + struct xwl_tablet_tool *xwl_tablet_tool, *next_xwl_tablet_tool; + struct xwl_tablet_pad *xwl_tablet_pad, *next_xwl_tablet_pad; + + xorg_list_for_each_entry_safe(xwl_tablet_pad, next_xwl_tablet_pad, + &xwl_seat->tablet_pads, link) { + xorg_list_del(&xwl_tablet_pad->link); + zwp_tablet_pad_v2_destroy(xwl_tablet_pad->pad); + free(xwl_tablet_pad); + } + + xorg_list_for_each_entry_safe(xwl_tablet_tool, next_xwl_tablet_tool, + &xwl_seat->tablet_tools, link) { + xorg_list_del(&xwl_tablet_tool->link); + zwp_tablet_tool_v2_destroy(xwl_tablet_tool->tool); + free(xwl_tablet_tool); + } + + xorg_list_for_each_entry_safe(xwl_tablet, next_xwl_tablet, + &xwl_seat->tablets, link) { + xorg_list_del(&xwl_tablet->link); + zwp_tablet_v2_destroy(xwl_tablet->tablet); + free(xwl_tablet); + } + + if (xwl_seat->tablet_seat) { + zwp_tablet_seat_v2_destroy(xwl_seat->tablet_seat); + xwl_seat->tablet_seat = NULL; + } +} + +static void +init_tablet_manager(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version) +{ + struct xwl_seat *xwl_seat; + + xwl_screen->tablet_manager = wl_registry_bind(xwl_screen->registry, + id, + &zwp_tablet_manager_v2_interface, + min(version,1)); + + xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) { + init_tablet_manager_seat(xwl_screen, xwl_seat); + } +} + +void +xwl_screen_release_tablet_manager(struct xwl_screen *xwl_screen) +{ + if (xwl_screen->tablet_manager) { + zwp_tablet_manager_v2_destroy(xwl_screen->tablet_manager); + xwl_screen->tablet_manager = NULL; + } +} + +static void init_relative_pointer_manager(struct xwl_screen *xwl_screen, uint32_t id, uint32_t version) { @@ -1198,6 +2440,27 @@ init_pointer_constraints(struct xwl_screen *xwl_screen, } static void +init_keyboard_grab(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version) +{ + struct xwl_seat *xwl_seat; + DeviceIntPtr master; + + xwl_screen->wp_grab = + wl_registry_bind(xwl_screen->registry, id, + &zwp_xwayland_keyboard_grab_manager_v1_interface, + 1); + + xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) { + if (xwl_seat->keyboard) { + master = GetMaster(xwl_seat->keyboard, MASTER_KEYBOARD); + if (master) + setup_keyboard_grab_handler(master); + } + } +} + +static void input_handler(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) { @@ -1210,6 +2473,10 @@ input_handler(void *data, struct wl_registry *registry, uint32_t id, init_relative_pointer_manager(xwl_screen, id, version); } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) { init_pointer_constraints(xwl_screen, id, version); + } else if (strcmp(interface, "zwp_tablet_manager_v2") == 0) { + init_tablet_manager(xwl_screen, id, version); + } else if (strcmp(interface, "zwp_xwayland_keyboard_grab_manager_v1") == 0) { + init_keyboard_grab(xwl_screen, id, version); } } @@ -1457,9 +2724,9 @@ xwl_pointer_warp_emulator_create(struct xwl_seat *xwl_seat) { struct xwl_pointer_warp_emulator *warp_emulator; - warp_emulator = calloc(sizeof *warp_emulator, 1); + warp_emulator = calloc(1, sizeof *warp_emulator); if (!warp_emulator) { - ErrorF("%s: ENOMEM", __func__); + ErrorF("%s: ENOMEM\n", __func__); return NULL; } diff --git a/xserver/hw/xwayland/xwayland-output.c b/xserver/hw/xwayland/xwayland-output.c index 5a0f739f3..cc68f0340 100644 --- a/xserver/hw/xwayland/xwayland-output.c +++ b/xserver/hw/xwayland/xwayland-output.c @@ -38,6 +38,8 @@ RR_Reflect_X | \ RR_Reflect_Y) +static void xwl_output_get_xdg_output(struct xwl_output *xwl_output); + static Rotation wl_transform_to_xrandr(enum wl_output_transform transform) { @@ -93,9 +95,12 @@ output_handle_geometry(void *data, struct wl_output *wl_output, int x, int y, physical_width, physical_height); RROutputSetSubpixelOrder(xwl_output->randr_output, wl_subpixel_to_xrandr(subpixel)); - xwl_output->x = x; - xwl_output->y = y; + /* Apply the change from wl_output only if xdg-output is not supported */ + if (!xwl_output->xdg_output) { + xwl_output->x = x; + xwl_output->y = y; + } xwl_output->rotation = wl_transform_to_xrandr(transform); } @@ -108,18 +113,22 @@ output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, if (!(flags & WL_OUTPUT_MODE_CURRENT)) return; - xwl_output->width = width; - xwl_output->height = height; + /* Apply the change from wl_output only if xdg-output is not supported */ + if (!xwl_output->xdg_output) { + xwl_output->width = width; + xwl_output->height = height; + } xwl_output->refresh = refresh; } static inline void output_get_new_size(struct xwl_output *xwl_output, + Bool need_rotate, int *height, int *width) { int output_width, output_height; - if (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) { + if (!need_rotate || (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180))) { output_width = xwl_output->width; output_height = xwl_output->height; } else { @@ -137,8 +146,9 @@ output_get_new_size(struct xwl_output *xwl_output, /* Approximate some kind of mmpd (m.m. per dot) of the screen given the outputs * associated with it. * - * It will either calculate the mean mmpd of all the outputs, or default to - * 96 DPI if no reasonable value could be calculated. + * It either calculates the mean mmpd of all the outputs or, if no reasonable + * value could be calculated, defaults to the mmpd of a screen with a DPI value + * of DEFAULT_DPI. */ static double approximate_mmpd(struct xwl_screen *xwl_screen) @@ -199,14 +209,32 @@ update_screen_size(struct xwl_output *xwl_output, int width, int height) } static void -output_handle_done(void *data, struct wl_output *wl_output) +apply_output_change(struct xwl_output *xwl_output) { - struct xwl_output *it, *xwl_output = data; struct xwl_screen *xwl_screen = xwl_output->xwl_screen; + struct xwl_output *it; + int mode_width, mode_height; int width = 0, height = 0, has_this_output = 0; RRModePtr randr_mode; + Bool need_rotate; - randr_mode = xwayland_cvt(xwl_output->width, xwl_output->height, + /* Clear out the "done" received flags */ + xwl_output->wl_output_done = FALSE; + xwl_output->xdg_output_done = FALSE; + + /* xdg-output sends output size in compositor space. so already rotated */ + need_rotate = (xwl_output->xdg_output == NULL); + + /* We need to rotate back the logical size for the mode */ + if (need_rotate || xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) { + mode_width = xwl_output->width; + mode_height = xwl_output->height; + } else { + mode_width = xwl_output->height; + mode_height = xwl_output->width; + } + + randr_mode = xwayland_cvt(mode_width, mode_height, xwl_output->refresh / 1000.0, 0, 0); RROutputSetModes(xwl_output->randr_output, &randr_mode, 1, 1); RRCrtcNotify(xwl_output->randr_crtc, randr_mode, @@ -221,14 +249,14 @@ output_handle_done(void *data, struct wl_output *wl_output) if (it == xwl_output) has_this_output = 1; - output_get_new_size(it, &height, &width); + output_get_new_size(it, need_rotate, &height, &width); } if (!has_this_output) { xorg_list_append(&xwl_output->link, &xwl_screen->output_list); /* we did not check this output for new screen size, do it now */ - output_get_new_size(xwl_output, &height, &width); + output_get_new_size(xwl_output, need_rotate, &height, &width); --xwl_screen->expecting_event; } @@ -237,6 +265,19 @@ output_handle_done(void *data, struct wl_output *wl_output) } static void +output_handle_done(void *data, struct wl_output *wl_output) +{ + struct xwl_output *xwl_output = data; + + xwl_output->wl_output_done = TRUE; + /* Apply the changes from wl_output only if both "done" events are received, + * or if xdg-output is not supported. + */ + if (xwl_output->xdg_output_done || !xwl_output->xdg_output) + apply_output_change(xwl_output); +} + +static void output_handle_scale(void *data, struct wl_output *wl_output, int32_t factor) { } @@ -248,6 +289,42 @@ static const struct wl_output_listener output_listener = { output_handle_scale }; +static void +xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, + int32_t x, int32_t y) +{ + struct xwl_output *xwl_output = data; + + xwl_output->x = x; + xwl_output->y = y; +} + +static void +xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, + int32_t width, int32_t height) +{ + struct xwl_output *xwl_output = data; + + xwl_output->width = width; + xwl_output->height = height; +} + +static void +xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) +{ + struct xwl_output *xwl_output = data; + + xwl_output->xdg_output_done = TRUE; + if (xwl_output->wl_output_done) + apply_output_change(xwl_output); +} + +static const struct zxdg_output_v1_listener xdg_output_listener = { + xdg_output_handle_logical_position, + xdg_output_handle_logical_size, + xdg_output_handle_done, +}; + struct xwl_output * xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id) { @@ -255,9 +332,9 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id) static int serial; char name[256]; - xwl_output = calloc(sizeof *xwl_output, 1); + xwl_output = calloc(1, sizeof *xwl_output); if (xwl_output == NULL) { - ErrorF("create_output ENOMEM\n"); + ErrorF("%s ENOMEM\n", __func__); return NULL; } @@ -292,6 +369,15 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id) RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1); RROutputSetConnection(xwl_output->randr_output, RR_Connected); + /* We want the output to be in the list as soon as created so we can + * use it when binding to the xdg-output protocol... + */ + xorg_list_append(&xwl_output->link, &xwl_screen->output_list); + --xwl_screen->expecting_event; + + if (xwl_screen->xdg_output_manager) + xwl_output_get_xdg_output(xwl_output); + return xwl_output; err: @@ -316,15 +402,17 @@ xwl_output_remove(struct xwl_output *xwl_output) struct xwl_output *it; struct xwl_screen *xwl_screen = xwl_output->xwl_screen; int width = 0, height = 0; + Bool need_rotate = (xwl_output->xdg_output == NULL); - RRCrtcDestroy(xwl_output->randr_crtc); - RROutputDestroy(xwl_output->randr_output); xorg_list_del(&xwl_output->link); xorg_list_for_each_entry(it, &xwl_screen->output_list, link) - output_get_new_size(it, &height, &width); + output_get_new_size(it, need_rotate, &height, &width); update_screen_size(xwl_output, width, height); + RRCrtcDestroy(xwl_output->randr_crtc); + RROutputDestroy(xwl_output->randr_output); + xwl_output_destroy(xwl_output); } @@ -359,3 +447,28 @@ xwl_screen_init_output(struct xwl_screen *xwl_screen) return TRUE; } + +static void +xwl_output_get_xdg_output(struct xwl_output *xwl_output) +{ + struct xwl_screen *xwl_screen = xwl_output->xwl_screen; + + xwl_output->xdg_output = + zxdg_output_manager_v1_get_xdg_output (xwl_screen->xdg_output_manager, + xwl_output->output); + + zxdg_output_v1_add_listener(xwl_output->xdg_output, + &xdg_output_listener, + xwl_output); +} + +void +xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen) +{ + struct xwl_output *it; + + assert(xwl_screen->xdg_output_manager); + + xorg_list_for_each_entry(it, &xwl_screen->output_list, link) + xwl_output_get_xdg_output(it); +} diff --git a/xserver/hw/xwayland/xwayland-present.c b/xserver/hw/xwayland/xwayland-present.c new file mode 100644 index 000000000..2937d9c97 --- /dev/null +++ b/xserver/hw/xwayland/xwayland-present.c @@ -0,0 +1,578 @@ +/* + * Copyright © 2018 Roman Gilg + * + * 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. + */ + +#include "xwayland.h" + +#include <present.h> + +/* + * When not flipping let Present copy with 60fps. + * When flipping wait on frame_callback, otherwise + * the surface is not visible, in this case update + * with long interval. + */ +#define TIMER_LEN_COPY 17 // ~60fps +#define TIMER_LEN_FLIP 1000 // 1fps + +static DevPrivateKeyRec xwl_present_window_private_key; + +static struct xwl_present_window * +xwl_present_window_priv(WindowPtr window) +{ + return dixGetPrivate(&window->devPrivates, + &xwl_present_window_private_key); +} + +static struct xwl_present_window * +xwl_present_window_get_priv(WindowPtr window) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + + if (xwl_present_window == NULL) { + xwl_present_window = calloc (1, sizeof (struct xwl_present_window)); + if (!xwl_present_window) + return NULL; + + xwl_present_window->window = window; + xwl_present_window->msc = 1; + xwl_present_window->ust = GetTimeInMicros(); + + xorg_list_init(&xwl_present_window->event_list); + xorg_list_init(&xwl_present_window->release_queue); + + dixSetPrivate(&window->devPrivates, + &xwl_present_window_private_key, + xwl_present_window); + } + + return xwl_present_window; +} + +static void +xwl_present_free_timer(struct xwl_present_window *xwl_present_window) +{ + TimerFree(xwl_present_window->frame_timer); + xwl_present_window->frame_timer = NULL; +} + +static CARD32 +xwl_present_timer_callback(OsTimerPtr timer, + CARD32 time, + void *arg); + +static inline Bool +xwl_present_has_events(struct xwl_present_window *xwl_present_window) +{ + return !!xwl_present_window->sync_flip || + !xorg_list_is_empty(&xwl_present_window->event_list); +} + +static void +xwl_present_reset_timer(struct xwl_present_window *xwl_present_window) +{ + if (xwl_present_has_events(xwl_present_window)) { + CARD32 timeout; + + if (xwl_present_window->frame_callback) + timeout = TIMER_LEN_FLIP; + else + timeout = TIMER_LEN_COPY; + + xwl_present_window->frame_timer = TimerSet(xwl_present_window->frame_timer, + 0, timeout, + &xwl_present_timer_callback, + xwl_present_window); + } else { + xwl_present_free_timer(xwl_present_window); + } +} + +void +xwl_present_cleanup(WindowPtr window) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + struct xwl_present_event *event, *tmp; + + if (!xwl_present_window) + return; + + if (xwl_present_window->frame_callback) { + wl_callback_destroy(xwl_present_window->frame_callback); + xwl_present_window->frame_callback = NULL; + } + + if (xwl_present_window->sync_callback) { + wl_callback_destroy(xwl_present_window->sync_callback); + xwl_present_window->sync_callback = NULL; + } + + /* Clear remaining events */ + xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->event_list, list) { + xorg_list_del(&event->list); + free(event); + } + + /* Clear remaining buffer releases and inform Present about free ressources */ + event = xwl_present_window->sync_flip; + xwl_present_window->sync_flip = NULL; + if (event) { + if (event->buffer_released) { + free(event); + } else { + event->pending = FALSE; + event->abort = TRUE; + } + } + xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->release_queue, list) { + xorg_list_del(&event->list); + event->abort = TRUE; + } + + /* Clear timer */ + xwl_present_free_timer(xwl_present_window); + + /* Remove from privates so we don't try to access it later */ + dixSetPrivate(&window->devPrivates, + &xwl_present_window_private_key, + NULL); + + free(xwl_present_window); +} + +static void +xwl_present_free_event(struct xwl_present_event *event) +{ + xorg_list_del(&event->list); + free(event); +} + +static void +xwl_present_buffer_release(void *data, struct wl_buffer *buffer) +{ + struct xwl_present_event *event = data; + if (!event) + return; + + wl_buffer_set_user_data(buffer, NULL); + event->buffer_released = TRUE; + + if (event->abort) { + if (!event->pending) + xwl_present_free_event(event); + return; + } + + if (!event->pending) { + present_wnmd_event_notify(event->xwl_present_window->window, + event->event_id, + event->xwl_present_window->ust, + event->xwl_present_window->msc); + xwl_present_free_event(event); + } +} + +static const struct wl_buffer_listener xwl_present_release_listener = { + xwl_present_buffer_release +}; + +static void +xwl_present_msc_bump(struct xwl_present_window *xwl_present_window) +{ + uint64_t msc = ++xwl_present_window->msc; + struct xwl_present_event *event, *tmp; + + xwl_present_window->ust = GetTimeInMicros(); + + event = xwl_present_window->sync_flip; + xwl_present_window->sync_flip = NULL; + if (event) { + event->pending = FALSE; + + present_wnmd_event_notify(xwl_present_window->window, event->event_id, + xwl_present_window->ust, msc); + + if (event->buffer_released) { + /* If the buffer was already released, clean up now */ + present_wnmd_event_notify(xwl_present_window->window, event->event_id, + xwl_present_window->ust, msc); + free(event); + } else { + xorg_list_add(&event->list, &xwl_present_window->release_queue); + } + } + + xorg_list_for_each_entry_safe(event, tmp, + &xwl_present_window->event_list, + list) { + if (event->target_msc <= msc) { + present_wnmd_event_notify(xwl_present_window->window, + event->event_id, + xwl_present_window->ust, + msc); + xwl_present_free_event(event); + } + } +} + +CARD32 +xwl_present_timer_callback(OsTimerPtr timer, + CARD32 time, + void *arg) +{ + struct xwl_present_window *xwl_present_window = arg; + + xwl_present_window->frame_timer_firing = TRUE; + + xwl_present_msc_bump(xwl_present_window); + xwl_present_reset_timer(xwl_present_window); + + return 0; +} + +static void +xwl_present_frame_callback(void *data, + struct wl_callback *callback, + uint32_t time) +{ + struct xwl_present_window *xwl_present_window = data; + + wl_callback_destroy(xwl_present_window->frame_callback); + xwl_present_window->frame_callback = NULL; + + if (xwl_present_window->frame_timer_firing) { + /* If the timer is firing, this frame callback is too late */ + return; + } + + xwl_present_msc_bump(xwl_present_window); + + /* we do not need the timer anymore for this frame, + * reset it for potentially the next one + */ + xwl_present_reset_timer(xwl_present_window); +} + +static const struct wl_callback_listener xwl_present_frame_listener = { + xwl_present_frame_callback +}; + +static void +xwl_present_sync_callback(void *data, + struct wl_callback *callback, + uint32_t time) +{ + struct xwl_present_event *event = data; + struct xwl_present_window *xwl_present_window = event->xwl_present_window; + + wl_callback_destroy(xwl_present_window->sync_callback); + xwl_present_window->sync_callback = NULL; + + event->pending = FALSE; + + if (event->abort) { + /* Event might have been aborted */ + if (event->buffer_released) + /* Buffer was already released, cleanup now */ + xwl_present_free_event(event); + return; + } + + present_wnmd_event_notify(xwl_present_window->window, + event->event_id, + xwl_present_window->ust, + xwl_present_window->msc); + + if (event->buffer_released) { + /* If the buffer was already released, send the event now again */ + present_wnmd_event_notify(xwl_present_window->window, + event->event_id, + xwl_present_window->ust, + xwl_present_window->msc); + xwl_present_free_event(event); + } +} + +static const struct wl_callback_listener xwl_present_sync_listener = { + xwl_present_sync_callback +}; + +static RRCrtcPtr +xwl_present_get_crtc(WindowPtr present_window) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window); + rrScrPrivPtr rr_private; + + if (xwl_present_window == NULL) + return NULL; + + rr_private = rrGetScrPriv(present_window->drawable.pScreen); + + if (rr_private->numCrtcs == 0) + return NULL; + + return rr_private->crtcs[0]; +} + +static int +xwl_present_get_ust_msc(WindowPtr present_window, uint64_t *ust, uint64_t *msc) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window); + if (!xwl_present_window) + return BadAlloc; + + *ust = xwl_present_window->ust; + *msc = xwl_present_window->msc; + + return Success; +} + +/* + * Queue an event to report back to the Present extension when the specified + * MSC has past + */ +static int +xwl_present_queue_vblank(WindowPtr present_window, + RRCrtcPtr crtc, + uint64_t event_id, + uint64_t msc) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window); + struct xwl_present_event *event; + + event = malloc(sizeof *event); + if (!event) + return BadAlloc; + + event->event_id = event_id; + event->xwl_present_window = xwl_present_window; + event->target_msc = msc; + + xorg_list_append(&event->list, &xwl_present_window->event_list); + + if (!xwl_present_window->frame_timer) + xwl_present_reset_timer(xwl_present_window); + + return Success; +} + +/* + * Remove a pending vblank event so that it is not reported + * to the extension + */ +static void +xwl_present_abort_vblank(WindowPtr present_window, + RRCrtcPtr crtc, + uint64_t event_id, + uint64_t msc) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(present_window); + struct xwl_present_event *event, *tmp; + + if (!xwl_present_window) + return; + + xorg_list_for_each_entry_safe(event, tmp, &xwl_present_window->event_list, list) { + if (event->event_id == event_id) { + xorg_list_del(&event->list); + free(event); + return; + } + } + + xorg_list_for_each_entry(event, &xwl_present_window->release_queue, list) { + if (event->event_id == event_id) { + event->abort = TRUE; + return; + } + } +} + +static void +xwl_present_flush(WindowPtr window) +{ + /* Only called when a Pixmap is copied instead of flipped, + * but in this case we wait on the next block_handler. + */ +} + +static Bool +xwl_present_check_flip2(RRCrtcPtr crtc, + WindowPtr present_window, + PixmapPtr pixmap, + Bool sync_flip, + PresentFlipReason *reason) +{ + struct xwl_window *xwl_window = xwl_window_from_window(present_window); + + if (!xwl_window) + return FALSE; + + /* + * We currently only allow flips of windows, that have the same + * dimensions as their xwl_window parent window. For the case of + * different sizes subsurfaces are presumably the way forward. + */ + if (!RegionEqual(&xwl_window->window->winSize, &present_window->winSize)) + return FALSE; + + return TRUE; +} + +static Bool +xwl_present_flip(WindowPtr present_window, + RRCrtcPtr crtc, + uint64_t event_id, + uint64_t target_msc, + PixmapPtr pixmap, + Bool sync_flip, + RegionPtr damage) +{ + struct xwl_window *xwl_window = xwl_window_from_window(present_window); + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(present_window); + BoxPtr damage_box; + Bool buffer_created; + struct wl_buffer *buffer; + struct xwl_present_event *event; + + if (!xwl_window) + return FALSE; + + damage_box = RegionExtents(damage); + + event = malloc(sizeof *event); + if (!event) + return FALSE; + + buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap, &buffer_created); + + event->event_id = event_id; + event->xwl_present_window = xwl_present_window; + event->buffer = buffer; + event->target_msc = target_msc; + event->pending = TRUE; + event->abort = FALSE; + event->buffer_released = FALSE; + + if (sync_flip) { + xorg_list_init(&event->list); + xwl_present_window->sync_flip = event; + } else { + xorg_list_add(&event->list, &xwl_present_window->release_queue); + } + + if (buffer_created) + wl_buffer_add_listener(buffer, &xwl_present_release_listener, NULL); + wl_buffer_set_user_data(buffer, event); + + /* We can flip directly to the main surface (full screen window without clips) */ + wl_surface_attach(xwl_window->surface, buffer, 0, 0); + + if (!xwl_present_window->frame_callback) { + xwl_present_window->frame_callback = wl_surface_frame(xwl_window->surface); + wl_callback_add_listener(xwl_present_window->frame_callback, + &xwl_present_frame_listener, + xwl_present_window); + } + + /* Realign timer */ + xwl_present_window->frame_timer_firing = FALSE; + xwl_present_reset_timer(xwl_present_window); + + wl_surface_damage(xwl_window->surface, 0, 0, + damage_box->x2 - damage_box->x1, + damage_box->y2 - damage_box->y1); + + wl_surface_commit(xwl_window->surface); + + if (!sync_flip) { + xwl_present_window->sync_callback = + wl_display_sync(xwl_window->xwl_screen->display); + wl_callback_add_listener(xwl_present_window->sync_callback, + &xwl_present_sync_listener, + event); + } + + wl_display_flush(xwl_window->xwl_screen->display); + xwl_window->present_flipped = TRUE; + return TRUE; +} + +static void +xwl_present_flips_stop(WindowPtr window) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + + /* Change back to the fast refresh rate */ + xwl_present_reset_timer(xwl_present_window); +} + +void +xwl_present_unrealize_window(WindowPtr window) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + + if (!xwl_present_window || !xwl_present_window->frame_callback) + return; + + /* The pending frame callback may never be called, so drop it and shorten + * the frame timer interval. + */ + wl_callback_destroy(xwl_present_window->frame_callback); + xwl_present_window->frame_callback = NULL; + xwl_present_reset_timer(xwl_present_window); +} + +static present_wnmd_info_rec xwl_present_info = { + .version = PRESENT_SCREEN_INFO_VERSION, + .get_crtc = xwl_present_get_crtc, + + .get_ust_msc = xwl_present_get_ust_msc, + .queue_vblank = xwl_present_queue_vblank, + .abort_vblank = xwl_present_abort_vblank, + + .flush = xwl_present_flush, + + .capabilities = PresentCapabilityAsync, + .check_flip2 = xwl_present_check_flip2, + .flip = xwl_present_flip, + .flips_stop = xwl_present_flips_stop +}; + +Bool +xwl_present_init(ScreenPtr screen) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(screen); + + /* + * doesn't work with the EGLStream backend. + */ + if (xwl_screen->egl_backend == &xwl_screen->eglstream_backend) + return FALSE; + + if (!dixRegisterPrivateKey(&xwl_present_window_private_key, PRIVATE_WINDOW, 0)) + return FALSE; + + return present_wnmd_screen_init(screen, &xwl_present_info); +} diff --git a/xserver/hw/xwayland/xwayland-shm.c b/xserver/hw/xwayland/xwayland-shm.c index 452d1f509..29732eaca 100644 --- a/xserver/hw/xwayland/xwayland-shm.c +++ b/xserver/hw/xwayland/xwayland-shm.c @@ -24,7 +24,7 @@ * SOFTWARE. */ -#ifdef HAVE_CONFIG_H +#ifdef HAVE_DIX_CONFIG_H #include <dix-config.h> #endif diff --git a/xserver/hw/xwayland/xwayland.c b/xserver/hw/xwayland/xwayland.c index d0bdf36a4..7e6e0ab25 100644 --- a/xserver/hw/xwayland/xwayland.c +++ b/xserver/hw/xwayland/xwayland.c @@ -27,13 +27,16 @@ #include <stdio.h> +#include <X11/Xatom.h> #include <selection.h> #include <micmap.h> #include <misyncshm.h> #include <compositeext.h> +#include <compint.h> #include <glx_extinit.h> #include <os.h> #include <xserver_poll.h> +#include <propertyst.h> #ifdef XF86VIDMODE #include <X11/extensions/xf86vmproto.h> @@ -71,12 +74,29 @@ ddxBeforeReset(void) } #endif + _X_NORETURN +static void _X_ATTRIBUTE_PRINTF(1, 2) +xwl_give_up(const char *f, ...) +{ + va_list args; + + va_start(args, f); + VErrorFSigSafe(f, args); + va_end(args); + + CloseWellKnownConnections(); + OsCleanup(TRUE); + fflush(stderr); + exit(1); +} + void ddxUseMsg(void) { ErrorF("-rootless run rootless, requires wm support\n"); ErrorF("-wm fd create X client for wm on given fd\n"); ErrorF("-listen fd add give fd as a listen socket\n"); + ErrorF("-eglstream use eglstream backend for nvidia GPUs\n"); } int @@ -95,6 +115,9 @@ ddxProcessArgument(int argc, char *argv[], int i) else if (strcmp(argv[i], "-shm") == 0) { return 1; } + else if (strcmp(argv[i], "-eglstream") == 0) { + return 1; + } return 0; } @@ -115,6 +138,94 @@ xwl_screen_get(ScreenPtr screen) return dixLookupPrivate(&screen->devPrivates, &xwl_screen_private_key); } +static void +xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow, + const char *debug_msg) +{ + xwl_window->allow_commits = allow; + DebugF("xwayland: win %d allow_commits = %d (%s)\n", + xwl_window->window->drawable.id, allow, debug_msg); +} + +static void +xwl_window_set_allow_commits_from_property(struct xwl_window *xwl_window, + PropertyPtr prop) +{ + static Bool warned = FALSE; + CARD32 *propdata; + + if (prop->propertyName != xwl_window->xwl_screen->allow_commits_prop) + FatalError("Xwayland internal error: prop mismatch in %s.\n", __func__); + + if (prop->type != XA_CARDINAL || prop->format != 32 || prop->size != 1) { + /* Not properly set, so fall back to safe and glitchy */ + xwl_window_set_allow_commits(xwl_window, TRUE, "WM fault"); + + if (!warned) { + LogMessage(X_WARNING, "Window manager is misusing property %s.\n", + NameForAtom(prop->propertyName)); + warned = TRUE; + } + return; + } + + propdata = prop->data; + xwl_window_set_allow_commits(xwl_window, !!propdata[0], "from property"); +} + +static void +xwl_window_property_allow_commits(struct xwl_window *xwl_window, + PropertyStateRec *propstate) +{ + Bool old_allow_commits = xwl_window->allow_commits; + + switch (propstate->state) { + case PropertyNewValue: + xwl_window_set_allow_commits_from_property(xwl_window, propstate->prop); + break; + + case PropertyDelete: + xwl_window_set_allow_commits(xwl_window, TRUE, "property deleted"); + break; + + default: + break; + } + + /* If allow_commits turned from off to on, discard any frame + * callback we might be waiting for so that a new buffer is posted + * immediately through block_handler() if there is damage to post. + */ + if (!old_allow_commits && xwl_window->allow_commits) { + if (xwl_window->frame_callback) { + wl_callback_destroy(xwl_window->frame_callback); + xwl_window->frame_callback = NULL; + } + } +} + +static void +xwl_property_callback(CallbackListPtr *pcbl, void *closure, + void *calldata) +{ + ScreenPtr screen = closure; + PropertyStateRec *rec = calldata; + struct xwl_screen *xwl_screen; + struct xwl_window *xwl_window; + + if (rec->win->drawable.pScreen != screen) + return; + + xwl_window = xwl_window_get(rec->win); + if (!xwl_window) + return; + + xwl_screen = xwl_screen_get(screen); + + if (rec->prop->propertyName == xwl_screen->allow_commits_prop) + xwl_window_property_allow_commits(xwl_window, rec); +} + static Bool xwl_close_screen(ScreenPtr screen) { @@ -122,6 +233,8 @@ xwl_close_screen(ScreenPtr screen) struct xwl_output *xwl_output, *next_xwl_output; struct xwl_seat *xwl_seat, *next_xwl_seat; + DeleteCallback(&PropertyStateCallback, xwl_property_callback, screen); + xorg_list_for_each_entry_safe(xwl_output, next_xwl_output, &xwl_screen->output_list, link) xwl_output_destroy(xwl_output); @@ -130,6 +243,8 @@ xwl_close_screen(ScreenPtr screen) &xwl_screen->seat_list, link) xwl_seat_destroy(xwl_seat); + xwl_screen_release_tablet_manager(xwl_screen); + RemoveNotifyFd(xwl_screen->wayland_fd); wl_display_disconnect(xwl_screen->display); @@ -140,7 +255,7 @@ xwl_close_screen(ScreenPtr screen) return screen->CloseScreen(screen); } -static struct xwl_window * +struct xwl_window * xwl_window_from_window(WindowPtr window) { struct xwl_window *xwl_window; @@ -183,6 +298,9 @@ xwl_cursor_warped_to(DeviceIntPtr device, if (!xwl_seat) xwl_seat = xwl_screen_get_default_seat(xwl_screen); + if (!window) + window = XYToWindow(sprite, x, y); + xwl_window = xwl_window_from_window(window); if (!xwl_window && xwl_seat->focus_window) { focus = xwl_seat->focus_window->window; @@ -252,6 +370,18 @@ damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data) struct xwl_window *xwl_window = data; struct xwl_screen *xwl_screen = xwl_window->xwl_screen; +#ifdef GLAMOR_HAS_GBM + if (xwl_window->present_flipped) { + /* This damage is from a Present flip, which already committed a new + * buffer for the surface, so we don't need to do anything in response + */ + RegionEmpty(DamageRegion(pDamage)); + xorg_list_del(&xwl_window->link_damage); + xwl_window->present_flipped = FALSE; + return; + } +#endif + xorg_list_add(&xwl_window->link_damage, &xwl_screen->damage_window_list); } @@ -298,6 +428,21 @@ xwl_pixmap_get(PixmapPtr pixmap) } static void +xwl_window_init_allow_commits(struct xwl_window *xwl_window) +{ + PropertyPtr prop = NULL; + int ret; + + ret = dixLookupProperty(&prop, xwl_window->window, + xwl_window->xwl_screen->allow_commits_prop, + serverClient, DixReadAccess); + if (ret == Success && prop) + xwl_window_set_allow_commits_from_property(xwl_window, prop); + else + xwl_window_set_allow_commits(xwl_window, TRUE, "no property"); +} + +static void send_surface_id_event(struct xwl_window *xwl_window) { static const char atom_name[] = "WL_SURFACE_ID"; @@ -357,7 +502,7 @@ xwl_realize_window(WindowPtr window) return ret; } - xwl_window = calloc(sizeof *xwl_window, 1); + xwl_window = calloc(1, sizeof *xwl_window); if (xwl_window == NULL) return FALSE; @@ -408,12 +553,16 @@ xwl_realize_window(WindowPtr window) goto err_surf; } + compRedirectWindow(serverClient, window, CompositeRedirectManual); + DamageRegister(&window->drawable, xwl_window->damage); DamageSetReportAfterOp(xwl_window->damage, TRUE); dixSetPrivate(&window->devPrivates, &xwl_window_private_key, xwl_window); xorg_list_init(&xwl_window->link_damage); + xwl_window_init_allow_commits(xwl_window); + return ret; err_surf: @@ -439,6 +588,8 @@ xwl_unrealize_window(WindowPtr window) xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) { if (xwl_seat->focus_window && xwl_seat->focus_window->window == window) xwl_seat->focus_window = NULL; + if (xwl_seat->tablet_focus_window && xwl_seat->tablet_focus_window->window == window) + xwl_seat->tablet_focus_window = NULL; if (xwl_seat->last_xwindow == window) xwl_seat->last_xwindow = NullWindow; if (xwl_seat->cursor_confinement_window && @@ -451,11 +602,18 @@ xwl_unrealize_window(WindowPtr window) xwl_seat_clear_touch(xwl_seat, window); } + compUnredirectWindow(serverClient, window, CompositeRedirectManual); + screen->UnrealizeWindow = xwl_screen->UnrealizeWindow; ret = (*screen->UnrealizeWindow) (window); xwl_screen->UnrealizeWindow = screen->UnrealizeWindow; screen->UnrealizeWindow = xwl_unrealize_window; +#ifdef GLAMOR_HAS_GBM + if (xwl_screen->present) + xwl_present_unrealize_window(window); +#endif + xwl_window = xwl_window_get(window); if (!xwl_window) return ret; @@ -494,45 +652,106 @@ static const struct wl_callback_listener frame_listener = { frame_callback }; +static Bool +xwl_destroy_window(WindowPtr window) +{ + ScreenPtr screen = window->drawable.pScreen; + struct xwl_screen *xwl_screen = xwl_screen_get(screen); + Bool ret; + +#ifdef GLAMOR_HAS_GBM + if (xwl_screen->present) + xwl_present_cleanup(window); +#endif + + screen->DestroyWindow = xwl_screen->DestroyWindow; + + if (screen->DestroyWindow) + ret = screen->DestroyWindow (window); + else + ret = TRUE; + + xwl_screen->DestroyWindow = screen->DestroyWindow; + screen->DestroyWindow = xwl_destroy_window; + + return ret; +} + static void -xwl_screen_post_damage(struct xwl_screen *xwl_screen) +xwl_window_post_damage(struct xwl_window *xwl_window) { - struct xwl_window *xwl_window, *next_xwl_window; + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; RegionPtr region; BoxPtr box; struct wl_buffer *buffer; PixmapPtr pixmap; + int i; - xorg_list_for_each_entry_safe(xwl_window, next_xwl_window, - &xwl_screen->damage_window_list, link_damage) { - /* If we're waiting on a frame callback from the server, - * don't attach a new buffer. */ - if (xwl_window->frame_callback) - continue; + assert(!xwl_window->frame_callback); - region = DamageRegion(xwl_window->damage); - pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->window); + region = DamageRegion(xwl_window->damage); + pixmap = (*xwl_screen->screen->GetWindowPixmap) (xwl_window->window); -#if GLAMOR_HAS_GBM - if (xwl_screen->glamor) - buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap); +#ifdef XWL_HAS_GLAMOR + if (xwl_screen->glamor) + buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap, + NULL); + else #endif - if (!xwl_screen->glamor) - buffer = xwl_shm_pixmap_get_wl_buffer(pixmap); + buffer = xwl_shm_pixmap_get_wl_buffer(pixmap); - wl_surface_attach(xwl_window->surface, buffer, 0, 0); +#ifdef XWL_HAS_GLAMOR + if (xwl_screen->glamor) + xwl_glamor_post_damage(xwl_window, pixmap, region); +#endif + + wl_surface_attach(xwl_window->surface, buffer, 0, 0); + /* Arbitrary limit to try to avoid flooding the Wayland + * connection. If we flood it too much anyway, this could + * abort in libwayland-client. + */ + if (RegionNumRects(region) > 256) { box = RegionExtents(region); wl_surface_damage(xwl_window->surface, box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1); + } else { + box = RegionRects(region); + for (i = 0; i < RegionNumRects(region); i++, box++) + wl_surface_damage(xwl_window->surface, box->x1, box->y1, + box->x2 - box->x1, box->y2 - box->y1); + } - xwl_window->frame_callback = wl_surface_frame(xwl_window->surface); - wl_callback_add_listener(xwl_window->frame_callback, &frame_listener, xwl_window); + xwl_window->frame_callback = wl_surface_frame(xwl_window->surface); + wl_callback_add_listener(xwl_window->frame_callback, &frame_listener, xwl_window); - wl_surface_commit(xwl_window->surface); - DamageEmpty(xwl_window->damage); + wl_surface_commit(xwl_window->surface); + DamageEmpty(xwl_window->damage); - xorg_list_del(&xwl_window->link_damage); + xorg_list_del(&xwl_window->link_damage); +} + +static void +xwl_screen_post_damage(struct xwl_screen *xwl_screen) +{ + struct xwl_window *xwl_window, *next_xwl_window; + + xorg_list_for_each_entry_safe(xwl_window, next_xwl_window, + &xwl_screen->damage_window_list, link_damage) { + /* If we're waiting on a frame callback from the server, + * don't attach a new buffer. */ + if (xwl_window->frame_callback) + continue; + + if (!xwl_window->allow_commits) + continue; + +#ifdef XWL_HAS_GLAMOR + if (xwl_screen->glamor && !xwl_glamor_allow_commits(xwl_window)) + continue; +#endif + + xwl_window_post_damage(xwl_window); } } @@ -557,10 +776,15 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id, if (xwl_output_create(xwl_screen, id)) xwl_screen->expecting_event++; } -#ifdef GLAMOR_HAS_GBM - else if (xwl_screen->glamor && - strcmp(interface, "wl_drm") == 0 && version >= 2) { - xwl_screen_init_glamor(xwl_screen, id, version); + else if (strcmp(interface, "zxdg_output_manager_v1") == 0) { + xwl_screen->xdg_output_manager = + wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, 1); + xwl_screen_init_xdg_output(xwl_screen); + } +#ifdef XWL_HAS_GLAMOR + else if (xwl_screen->glamor) { + xwl_glamor_init_wl_registry(xwl_screen, registry, id, interface, + version); } #endif } @@ -595,13 +819,13 @@ xwl_read_events (struct xwl_screen *xwl_screen) ret = wl_display_read_events(xwl_screen->display); if (ret == -1) - FatalError("failed to read Wayland events: %s\n", strerror(errno)); + xwl_give_up("failed to read Wayland events: %s\n", strerror(errno)); xwl_screen->prepare_read = 0; ret = wl_display_dispatch_pending(xwl_screen->display); if (ret == -1) - FatalError("failed to dispatch Wayland events: %s\n", strerror(errno)); + xwl_give_up("failed to dispatch Wayland events: %s\n", strerror(errno)); } static int @@ -628,7 +852,7 @@ xwl_dispatch_events (struct xwl_screen *xwl_screen) wl_display_prepare_read(xwl_screen->display) == -1) { ret = wl_display_dispatch_pending(xwl_screen->display); if (ret == -1) - FatalError("failed to dispatch Wayland events: %s\n", + xwl_give_up("failed to dispatch Wayland events: %s\n", strerror(errno)); } @@ -637,13 +861,13 @@ xwl_dispatch_events (struct xwl_screen *xwl_screen) pollout: ready = xwl_display_pollout(xwl_screen, 5); if (ready == -1 && errno != EINTR) - FatalError("error polling on XWayland fd: %s\n", strerror(errno)); + xwl_give_up("error polling on XWayland fd: %s\n", strerror(errno)); if (ready > 0) ret = wl_display_flush(xwl_screen->display); if (ret == -1 && errno != EAGAIN) - FatalError("failed to write to XWayland fd: %s\n", strerror(errno)); + xwl_give_up("failed to write to XWayland fd: %s\n", strerror(errno)); xwl_screen->wait_flush = (ready == 0 || ready == -1 || ret == -1); } @@ -721,11 +945,13 @@ wm_selection_callback(CallbackListPtr *p, void *data, void *arg) static Bool xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) { + static const char allow_commits[] = "_XWAYLAND_ALLOW_COMMITS"; struct xwl_screen *xwl_screen; Pixel red_mask, blue_mask, green_mask; int ret, bpc, green_bpc, i; + Bool use_eglstreams = FALSE; - xwl_screen = calloc(sizeof *xwl_screen, 1); + xwl_screen = calloc(1, sizeof *xwl_screen); if (xwl_screen == NULL) return FALSE; xwl_screen->wm_fd = -1; @@ -740,7 +966,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) dixSetPrivate(&pScreen->devPrivates, &xwl_screen_private_key, xwl_screen); xwl_screen->screen = pScreen; -#ifdef GLAMOR_HAS_GBM +#ifdef XWL_HAS_GLAMOR xwl_screen->glamor = 1; #endif @@ -756,7 +982,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) else if (strcmp(argv[i], "-listen") == 0) { if (xwl_screen->listen_fd_count == ARRAY_SIZE(xwl_screen->listen_fds)) - FatalError("Too many -listen arguments given, max is %ld\n", + FatalError("Too many -listen arguments given, max is %zu\n", ARRAY_SIZE(xwl_screen->listen_fds)); xwl_screen->listen_fds[xwl_screen->listen_fd_count++] = @@ -766,8 +992,20 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) else if (strcmp(argv[i], "-shm") == 0) { xwl_screen->glamor = 0; } + else if (strcmp(argv[i], "-eglstream") == 0) { +#ifdef XWL_HAS_EGLSTREAM + use_eglstreams = TRUE; +#else + ErrorF("xwayland glamor: this build does not have EGLStream support\n"); +#endif + } } +#ifdef XWL_HAS_GLAMOR + if (xwl_screen->glamor) + xwl_glamor_init_backends(xwl_screen, use_eglstreams); +#endif + /* In rootless mode, we don't have any screen storage, and the only * rendering should be to redirected mode. */ if (xwl_screen->rootless) @@ -850,11 +1088,18 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) if (!xwl_screen_init_cursor(xwl_screen)) return FALSE; -#ifdef GLAMOR_HAS_GBM - if (xwl_screen->glamor && !xwl_glamor_init(xwl_screen)) { - ErrorF("Failed to initialize glamor, falling back to sw\n"); - xwl_screen->glamor = 0; +#ifdef XWL_HAS_GLAMOR + if (xwl_screen->glamor) { + xwl_glamor_select_backend(xwl_screen, use_eglstreams); + + if (xwl_screen->egl_backend == NULL || !xwl_glamor_init(xwl_screen)) { + ErrorF("Failed to initialize glamor, falling back to sw\n"); + xwl_screen->glamor = 0; + } } + + if (xwl_screen->glamor && xwl_screen->rootless) + xwl_screen->present = xwl_present_init(pScreen); #endif if (!xwl_screen->glamor) { @@ -870,12 +1115,27 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) xwl_screen->UnrealizeWindow = pScreen->UnrealizeWindow; pScreen->UnrealizeWindow = xwl_unrealize_window; + xwl_screen->DestroyWindow = pScreen->DestroyWindow; + pScreen->DestroyWindow = xwl_destroy_window; + xwl_screen->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = xwl_close_screen; pScreen->CursorWarpedTo = xwl_cursor_warped_to; pScreen->CursorConfinedTo = xwl_cursor_confined_to; + xwl_screen->allow_commits_prop = MakeAtom(allow_commits, + strlen(allow_commits), + TRUE); + if (xwl_screen->allow_commits_prop == BAD_RESOURCE) + return FALSE; + + AddCallback(&PropertyStateCallback, xwl_property_callback, pScreen); + + wl_display_roundtrip(xwl_screen->display); + while (xwl_screen->expecting_event) + wl_display_roundtrip(xwl_screen->display); + return ret; } @@ -890,9 +1150,6 @@ xwl_log_handler(const char *format, va_list args) } static const ExtensionModule xwayland_extensions[] = { -#ifdef GLXEXT - { GlxExtensionInit, "GLX", &noGlxExtension }, -#endif #ifdef XF86VIDMODE { xwlVidModeExtensionInit, XF86VIDMODENAME, &noXFree86VidModeExtension }, #endif @@ -930,5 +1187,7 @@ InitOutput(ScreenInfo * screen_info, int argc, char **argv) FatalError("Couldn't add screen\n"); } + xorgGlxCreateVendor(); + LocalAccessScopeUser(); } diff --git a/xserver/hw/xwayland/xwayland.h b/xserver/hw/xwayland/xwayland.h index 5e5624be0..463622669 100644 --- a/xserver/hw/xwayland/xwayland.h +++ b/xserver/hw/xwayland/xwayland.h @@ -26,7 +26,7 @@ #ifndef XWAYLAND_H #define XWAYLAND_H -#include <dix-config.h> +#include <xwayland-config.h> #include <stdio.h> #include <unistd.h> @@ -44,6 +44,73 @@ #include "relative-pointer-unstable-v1-client-protocol.h" #include "pointer-constraints-unstable-v1-client-protocol.h" +#include "tablet-unstable-v2-client-protocol.h" +#include "xwayland-keyboard-grab-unstable-v1-client-protocol.h" +#include "xdg-output-unstable-v1-client-protocol.h" +#include "linux-dmabuf-unstable-v1-client-protocol.h" + +struct xwl_format { + uint32_t format; + int num_modifiers; + uint64_t *modifiers; +}; + +struct xwl_pixmap; +struct xwl_window; +struct xwl_screen; + +struct xwl_egl_backend { + /* Set by the backend if available */ + Bool is_available; + + /* Called once for each interface in the global registry. Backends + * should use this to bind to any wayland interfaces they need. + */ + Bool (*init_wl_registry)(struct xwl_screen *xwl_screen, + struct wl_registry *wl_registry, + uint32_t id, const char *name, + uint32_t version); + + /* Check that the required Wayland interfaces are available. + */ + Bool (*has_wl_interfaces)(struct xwl_screen *xwl_screen); + + /* Called before glamor has been initialized. Backends should setup a + * valid, glamor compatible EGL context in this hook. + */ + Bool (*init_egl)(struct xwl_screen *xwl_screen); + + /* Called after glamor has been initialized, and after all of the + * common Xwayland DDX hooks have been connected. Backends should use + * this to setup any required wraps around X server callbacks like + * CreatePixmap. + */ + Bool (*init_screen)(struct xwl_screen *xwl_screen); + + /* Called by Xwayland to retrieve a pointer to a valid wl_buffer for + * the given window/pixmap combo so that damage to the pixmap may be + * displayed on-screen. Backends should use this to create a new + * wl_buffer for a currently buffer-less pixmap, or simply return the + * pixmap they've prepared beforehand. + */ + struct wl_buffer *(*get_wl_buffer_for_pixmap)(PixmapPtr pixmap, + Bool *created); + + /* Called by Xwayland to perform any pre-wl_surface damage routines + * that are required by the backend. If your backend is poorly + * designed and lacks the ability to render directly to a surface, + * you should implement blitting from the glamor pixmap to the wayland + * pixmap here. Otherwise, this callback is optional. + */ + void (*post_damage)(struct xwl_window *xwl_window, + PixmapPtr pixmap, RegionPtr region); + + /* Called by Xwayland to confirm with the egl backend that the given + * pixmap is completely setup and ready for display on-screen. This + * callback is optional. + */ + Bool (*allow_commits)(struct xwl_window *xwl_window); +}; struct xwl_screen { int width; @@ -58,13 +125,13 @@ struct xwl_screen { int listen_fd_count; int rootless; int glamor; + int present; CreateScreenResourcesProcPtr CreateScreenResources; CloseScreenProcPtr CloseScreen; - CreateWindowProcPtr CreateWindow; - DestroyWindowProcPtr DestroyWindow; RealizeWindowProcPtr RealizeWindow; UnrealizeWindowProcPtr UnrealizeWindow; + DestroyWindowProcPtr DestroyWindow; XYToWindowProcPtr XYToWindow; struct xorg_list output_list; @@ -76,11 +143,13 @@ struct xwl_screen { struct wl_registry *registry; struct wl_registry *input_registry; struct wl_compositor *compositor; + struct zwp_tablet_manager_v2 *tablet_manager; struct wl_shm *shm; struct wl_shell *shell; struct zwp_relative_pointer_manager_v1 *relative_pointer_manager; struct zwp_pointer_constraints_v1 *pointer_constraints; - + struct zwp_xwayland_keyboard_grab_manager_v1 *wp_grab; + struct zxdg_output_manager_v1 *xdg_output_manager; uint32_t serial; #define XWL_FORMAT_ARGB8888 (1 << 0) @@ -90,15 +159,18 @@ struct xwl_screen { int prepare_read; int wait_flush; - char *device_name; - int drm_fd; - int fd_render_node; - struct wl_drm *drm; - uint32_t formats; - uint32_t capabilities; + uint32_t num_formats; + struct xwl_format *formats; void *egl_display, *egl_context; - struct gbm_device *gbm; + + struct xwl_egl_backend gbm_backend; + struct xwl_egl_backend eglstream_backend; + /* pointer to the current backend for creating pixmaps on wayland */ + struct xwl_egl_backend *egl_backend; + struct glamor_context *glamor_ctx; + + Atom allow_commits_prop; }; struct xwl_window { @@ -109,8 +181,47 @@ struct xwl_window { DamagePtr damage; struct xorg_list link_damage; struct wl_callback *frame_callback; + Bool allow_commits; +#ifdef GLAMOR_HAS_GBM + Bool present_flipped; +#endif +}; + +#ifdef GLAMOR_HAS_GBM +struct xwl_present_window { + struct xwl_screen *xwl_screen; + struct xwl_present_event *sync_flip; + WindowPtr window; + struct xorg_list link; + + uint64_t msc; + uint64_t ust; + + OsTimerPtr frame_timer; + Bool frame_timer_firing; + + struct wl_callback *frame_callback; + struct wl_callback *sync_callback; + + struct xorg_list event_list; + struct xorg_list release_queue; }; +struct xwl_present_event { + uint64_t event_id; + uint64_t target_msc; + + Bool abort; + Bool pending; + Bool buffer_released; + + struct xwl_present_window *xwl_present_window; + struct wl_buffer *buffer; + + struct xorg_list list; +}; +#endif + #define MODIFIER_META 0x01 struct xwl_touch { @@ -126,26 +237,36 @@ struct xwl_pointer_warp_emulator { struct zwp_locked_pointer_v1 *locked_pointer; }; +struct xwl_cursor { + void (* update_proc) (struct xwl_cursor *); + struct wl_surface *surface; + struct wl_callback *frame_cb; + Bool needs_update; +}; + struct xwl_seat { DeviceIntPtr pointer; DeviceIntPtr relative_pointer; DeviceIntPtr keyboard; DeviceIntPtr touch; + DeviceIntPtr stylus; + DeviceIntPtr eraser; + DeviceIntPtr puck; struct xwl_screen *xwl_screen; struct wl_seat *seat; struct wl_pointer *wl_pointer; struct zwp_relative_pointer_v1 *wp_relative_pointer; struct wl_keyboard *wl_keyboard; struct wl_touch *wl_touch; + struct zwp_tablet_seat_v2 *tablet_seat; struct wl_array keys; struct xwl_window *focus_window; + struct xwl_window *tablet_focus_window; uint32_t id; uint32_t pointer_enter_serial; struct xorg_list link; CursorPtr x_cursor; - struct wl_surface *cursor; - struct wl_callback *cursor_frame_cb; - Bool cursor_needs_update; + struct xwl_cursor cursor; WindowPtr last_xwindow; struct xorg_list touches; @@ -154,6 +275,7 @@ struct xwl_seat { char *keymap; struct wl_surface *keyboard_focus; + struct xorg_list axis_discrete_pending; struct xorg_list sync_pending; struct xwl_pointer_warp_emulator *pointer_warp_emulator; @@ -172,27 +294,97 @@ struct xwl_seat { double dx_unaccel; double dy_unaccel; } pending_pointer_event; + + struct xorg_list tablets; + struct xorg_list tablet_tools; + struct xorg_list tablet_pads; + struct zwp_xwayland_keyboard_grab_v1 *keyboard_grab; +}; + +struct xwl_tablet { + struct xorg_list link; + struct zwp_tablet_v2 *tablet; + struct xwl_seat *seat; +}; + +struct xwl_tablet_tool { + struct xorg_list link; + struct zwp_tablet_tool_v2 *tool; + struct xwl_seat *seat; + + DeviceIntPtr xdevice; + uint32_t proximity_in_serial; + double x; + double y; + uint32_t pressure; + double tilt_x; + double tilt_y; + double rotation; + double slider; + + uint32_t buttons_now, + buttons_prev; + + int32_t wheel_clicks; + + struct xwl_cursor cursor; +}; + +struct xwl_tablet_pad_ring { + unsigned int index; + struct xorg_list link; + struct xwl_tablet_pad_group *group; + struct zwp_tablet_pad_ring_v2 *ring; +}; + +struct xwl_tablet_pad_strip { + unsigned int index; + struct xorg_list link; + struct xwl_tablet_pad_group *group; + struct zwp_tablet_pad_strip_v2 *strip; +}; + +struct xwl_tablet_pad_group { + struct xorg_list link; + struct xwl_tablet_pad *pad; + struct zwp_tablet_pad_group_v2 *group; + + struct xorg_list pad_group_ring_list; + struct xorg_list pad_group_strip_list; +}; + +struct xwl_tablet_pad { + struct xorg_list link; + struct zwp_tablet_pad_v2 *pad; + struct xwl_seat *seat; + + DeviceIntPtr xdevice; + + unsigned int nbuttons; + struct xorg_list pad_group_list; }; struct xwl_output { struct xorg_list link; struct wl_output *output; + struct zxdg_output_v1 *xdg_output; uint32_t server_output_id; struct xwl_screen *xwl_screen; RROutputPtr randr_output; RRCrtcPtr randr_crtc; int32_t x, y, width, height, refresh; Rotation rotation; + Bool wl_output_done; + Bool xdg_output_done; }; -struct xwl_pixmap; - void xwl_sync_events (struct xwl_screen *xwl_screen); Bool xwl_screen_init_cursor(struct xwl_screen *xwl_screen); struct xwl_screen *xwl_screen_get(ScreenPtr screen); +void xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *tool); void xwl_seat_set_cursor(struct xwl_seat *xwl_seat); void xwl_seat_destroy(struct xwl_seat *xwl_seat); @@ -227,6 +419,7 @@ RRModePtr xwayland_cvt(int HDisplay, int VDisplay, void xwl_pixmap_set_private(PixmapPtr pixmap, struct xwl_pixmap *xwl_pixmap); struct xwl_pixmap *xwl_pixmap_get(PixmapPtr pixmap); +struct xwl_window *xwl_window_from_window(WindowPtr window); Bool xwl_shm_create_screen_resources(ScreenPtr screen); PixmapPtr xwl_shm_create_pixmap(ScreenPtr screen, int width, int height, @@ -234,20 +427,65 @@ PixmapPtr xwl_shm_create_pixmap(ScreenPtr screen, int width, int height, Bool xwl_shm_destroy_pixmap(PixmapPtr pixmap); struct wl_buffer *xwl_shm_pixmap_get_wl_buffer(PixmapPtr pixmap); - +#ifdef XWL_HAS_GLAMOR +void xwl_glamor_init_backends(struct xwl_screen *xwl_screen, + Bool use_eglstream); +void xwl_glamor_select_backend(struct xwl_screen *xwl_screen, + Bool use_eglstream); Bool xwl_glamor_init(struct xwl_screen *xwl_screen); -Bool xwl_screen_init_glamor(struct xwl_screen *xwl_screen, - uint32_t id, uint32_t version); -struct wl_buffer *xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap); +Bool xwl_screen_set_drm_interface(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version); +Bool xwl_screen_set_dmabuf_interface(struct xwl_screen *xwl_screen, + uint32_t id, uint32_t version); +struct wl_buffer *xwl_glamor_pixmap_get_wl_buffer(PixmapPtr pixmap, + Bool *created); +void xwl_glamor_init_wl_registry(struct xwl_screen *xwl_screen, + struct wl_registry *registry, + uint32_t id, const char *interface, + uint32_t version); +Bool xwl_glamor_has_wl_interfaces(struct xwl_screen *xwl_screen, + struct xwl_egl_backend *xwl_egl_backend); +void xwl_glamor_post_damage(struct xwl_window *xwl_window, + PixmapPtr pixmap, RegionPtr region); +Bool xwl_glamor_allow_commits(struct xwl_window *xwl_window); +void xwl_glamor_egl_make_current(struct xwl_screen *xwl_screen); + +#ifdef GLAMOR_HAS_GBM +Bool xwl_present_init(ScreenPtr screen); +void xwl_present_cleanup(WindowPtr window); +void xwl_present_unrealize_window(WindowPtr window); +#endif /* GLAMOR_HAS_GBM */ #ifdef XV /* glamor Xv Adaptor */ Bool xwl_glamor_xv_init(ScreenPtr pScreen); -#endif +#endif /* XV */ + +#endif /* XWL_HAS_GLAMOR */ + +void xwl_screen_release_tablet_manager(struct xwl_screen *xwl_screen); + +void xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen); #ifdef XF86VIDMODE void xwlVidModeExtensionInit(void); #endif +#ifdef GLAMOR_HAS_GBM +void xwl_glamor_init_gbm(struct xwl_screen *xwl_screen); +#else +static inline void xwl_glamor_init_gbm(struct xwl_screen *xwl_screen) +{ +} +#endif + +#ifdef XWL_HAS_EGLSTREAM +void xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen); +#else +static inline void xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen) +{ +} +#endif + #endif |