Compare commits
240 Commits
xwayland-2
...
scaling-mr
Author | SHA1 | Date |
---|---|---|
Andrea Cavalli | ea5e7c688e | |
Andrea Cavalli | f5a4fe32db | |
Andrea Cavalli | 672bba9ed0 | |
Andrea Cavalli | d448ffcb05 | |
Andrea Cavalli | 012d982d90 | |
Andrea Cavalli | 6d2e5cd62e | |
Andrea Cavalli | e2d60a037c | |
Andrea Cavalli | 52687e0853 | |
Ryan Gonzalez | 18f1ce0b6e | |
Ryan Gonzalez | aa849658c5 | |
Christopher Snowhill | b46a9bba29 | |
Dario Nieuwenhuis | fbc7cefc43 | |
Povilas Kanapickas | 18d3131f9a | |
Povilas Kanapickas | 722da1c62c | |
Adam Jackson | 1f720dc9a3 | |
Adam Jackson | b49f0f9b32 | |
Adam Jackson | c1138d8ec8 | |
Adam Jackson | f3a98334e6 | |
Simon Ser | 6f63873da5 | |
Demi Marie Obenour | 659260a0b7 | |
Roman Gilg | e4dabe8d93 | |
Demi Marie Obenour | 31fb35a7af | |
Olivier Fourdan | 7eba412072 | |
Olivier Fourdan | f2781e9536 | |
Olivier Fourdan | f788289bdc | |
Olivier Fourdan | 6ea2c001f9 | |
Olivier Fourdan | a4ab57cb74 | |
Olivier Fourdan | 84897891e5 | |
Demi Marie Obenour | 5c2592cbb1 | |
Alex Richardson | d83c84bd9d | |
Zoltán Böszörményi | fb5322ce28 | |
Zoltán Böszörményi | f08bc32f5a | |
Zoltán Böszörményi | cd567415cc | |
Boris-Barboris | 16571b8926 | |
Łukasz Spintzyk | 8836b9d243 | |
Łukasz Spintzyk | d6c02ffd9c | |
Michel Dänzer | f6f2f203bc | |
Michel Dänzer | 212cfbcf68 | |
Michel Dänzer | fe8c7855f3 | |
Michel Dänzer | 31d2ebca77 | |
Michel Dänzer | 495ec59664 | |
Michel Dänzer | f73340445f | |
Michel Dänzer | aac31d2758 | |
Michel Dänzer | f8c086b214 | |
Michel Dänzer | c30f3d08ac | |
Michel Dänzer | 4503c8d9ea | |
Michel Dänzer | b2a06e0700 | |
Michel Dänzer | fc53e3c536 | |
Michel Dänzer | c592c66625 | |
Michel Dänzer | 4230176080 | |
Michel Dänzer | 61cc5d96ed | |
Michel Dänzer | 35f173ddb6 | |
Michel Dänzer | 0517460301 | |
Michel Dänzer | 490248ea70 | |
Michel Dänzer | 0c0cbbc7cb | |
Michel Dänzer | 561c63d0f1 | |
Michel Dänzer | a67f16fde1 | |
Michel Dänzer | 080c1ca3f5 | |
Michel Dänzer | c22887bc7a | |
Michel Dänzer | cb35ff596e | |
Michel Dänzer | 7b78cf6b3a | |
Michel Dänzer | 244403ec87 | |
Michel Dänzer | f7adbc2166 | |
Michel Dänzer | 7fd114365d | |
Michel Dänzer | 2e1dcd731f | |
Michel Dänzer | b6419359b6 | |
Michel Dänzer | c35a716b02 | |
Michel Dänzer | 10bdd87fe4 | |
Michel Dänzer | b6d54b0f5d | |
Michel Dänzer | 93666ebe37 | |
Michel Dänzer | 44f705a5b6 | |
Michel Dänzer | 86e645bcfa | |
Michel Dänzer | ba8763c27b | |
Michel Dänzer | 204f10c29e | |
Michel Dänzer | a6d178b6af | |
Matt Turner | 7e20c8b7b8 | |
Dave Airlie | a955286869 | |
Dave Airlie | a2f5b917f5 | |
Povilas Kanapickas | b4f55712da | |
Povilas Kanapickas | b67e514dbb | |
Adam Jackson | b2a0de4f07 | |
Olivier Fourdan | 7d509b6f34 | |
Olivier Fourdan | 2be9f795bc | |
orbea | 2531ee0245 | |
Povilas Kanapickas | 2f53d1cf73 | |
Olivier Certner | d4b38e1119 | |
Łukasz Spintzyk | d66b7ec129 | |
Povilas Kanapickas | 0d93bbfa2c | |
Povilas Kanapickas | 303763941f | |
Povilas Kanapickas | b9722d39cd | |
Zoltán Böszörményi | ef89b6648e | |
Olivier Fourdan | aad61e8e03 | |
Povilas Kanapickas | 021b3c2f77 | |
Daniel Strnad | 05b3c681ea | |
Łukasz Spintzyk | f8a6be04d0 | |
Povilas Kanapickas | 1a1bd5cf7a | |
Povilas Kanapickas | 9992245c5f | |
Jose Maria Casanova Crespo | 9adb13e296 | |
Michel Dänzer | 104c7c5048 | |
Michel Dänzer | 3641c24bd0 | |
Michel Dänzer | d163e0a1d5 | |
Lukasz Spintzyk | 7e7c147105 | |
Olivier Fourdan | c468d34c72 | |
Olivier Fourdan | 6b47321bc6 | |
Olivier Fourdan | e167299f60 | |
Erik Kurzinger | b7a85e44da | |
Jan Beich | 8274dd6643 | |
Olivier Fourdan | 34a58d7714 | |
Olivier Fourdan | fae58e9b03 | |
Olivier Fourdan | 24fc8aea1e | |
Niveditha Rau | 2de5ded3c6 | |
Adam Jackson | bcb1de600a | |
Povilas Kanapickas | eb6f8daca5 | |
Povilas Kanapickas | 7e692633fb | |
Povilas Kanapickas | 0886254f96 | |
Povilas Kanapickas | 1cdc3b5d14 | |
Povilas Kanapickas | dccc0275f4 | |
Povilas Kanapickas | 75feb13668 | |
Povilas Kanapickas | 5163fc8bc2 | |
Povilas Kanapickas | d3c52df161 | |
Povilas Kanapickas | 100a2ad6da | |
Povilas Kanapickas | 7656a9c8dd | |
Povilas Kanapickas | 0bf4123fd3 | |
Povilas Kanapickas | 227f601de3 | |
Povilas Kanapickas | f3462178ca | |
Povilas Kanapickas | 407a2234b3 | |
Povilas Kanapickas | f83f7dbb1c | |
Povilas Kanapickas | 8190954639 | |
Povilas Kanapickas | 080bac39c8 | |
Povilas Kanapickas | b544a1fdb8 | |
Povilas Kanapickas | 22fa31ed56 | |
Povilas Kanapickas | 8e504d8b36 | |
Povilas Kanapickas | 2acde60147 | |
Claes Nästén | 236d177550 | |
Erik Kurzinger | 7515c23a41 | |
Simon Ser | f3eb1684fa | |
Erik Kurzinger | 3d33d885fc | |
Olivier Fourdan | 012350e3db | |
Olivier Fourdan | d85bfa6ab7 | |
Olivier Fourdan | b583395cd3 | |
Olivier Fourdan | a457999710 | |
Olivier Fourdan | 098e0f52c0 | |
Olivier Fourdan | bee2ebb29f | |
Olivier Fourdan | e19bf86c17 | |
Olivier Fourdan | cb61ecc729 | |
Olivier Fourdan | cc596bcfb2 | |
Olivier Fourdan | 823f3254fa | |
Olivier Fourdan | 85244d2a20 | |
Olivier Fourdan | 252cbad316 | |
Olivier Fourdan | 3b265c59a6 | |
Olivier Fourdan | 25d2f4948f | |
Olivier Fourdan | 4f0889e983 | |
Erik Kurzinger | 4f6fbd5009 | |
qarmin | a50a0e3485 | |
Mazlan, Hazwan Arif | 3ea46f9336 | |
Jon Turney | d3933a24d1 | |
luporl | 7e142cb2a8 | |
Łukasz Spintzyk | 5be3b80b8d | |
Łukasz Spintzyk | c282be503e | |
Łukasz Spintzyk | b923364c5e | |
Łukasz Spintzyk | d2dce22b67 | |
Łukasz Spintzyk | 908deb0895 | |
Łukasz Spintzyk | d03c0de77b | |
Matthieu Herrb | 7aaf54a188 | |
Peter Hutterer | 66ce61983d | |
Peter Hutterer | f6b8f8c071 | |
Jan Beich | eceafd4a2d | |
Jan Beich | 9f8421af63 | |
Erik Kurzinger | 38e875904b | |
Erik Kurzinger | bc99dd2127 | |
Erik Kurzinger | 400d4d0fdd | |
Olivier Fourdan | ae225417c0 | |
Povilas Kanapickas | d231ce2d9c | |
Povilas Kanapickas | 68c2cfadd6 | |
Povilas Kanapickas | faff5bbdf5 | |
Povilas Kanapickas | b25795462f | |
Povilas Kanapickas | 9582ef4efc | |
Povilas Kanapickas | 689496ed65 | |
Povilas Kanapickas | 2df55813d0 | |
Adam Jackson | 5d3679104a | |
George Matsumura | 3e4e70db10 | |
Edouard Gaulué | 199f278a1b | |
Jeremy Huddleston Sequoia | 65b27d82f2 | |
Pascal VITOUX | 34e2a64ce0 | |
Aaron Plattner | b75d0cca28 | |
Jeremie Courreges-Anglas | ab8f8c9841 | |
Povilas Kanapickas | aeed57d722 | |
Povilas Kanapickas | a3931ec6f4 | |
Povilas Kanapickas | 09cd65233e | |
Povilas Kanapickas | 88b5e1a219 | |
Povilas Kanapickas | 82d2156ba7 | |
Povilas Kanapickas | ba51acb1de | |
Povilas Kanapickas | 99e7ccffb3 | |
Simon Ser | 1b7dca27eb | |
Michel Dänzer | 6c51818a0f | |
Jan Beich | 376eaadde3 | |
Jeremy Huddleston Sequoia | 4ae36f418e | |
Matthieu Herrb | b2d96b5cd4 | |
Jeremy Huddleston Sequoia | 15a413e11d | |
Jeremy Huddleston Sequoia | e59848548a | |
Olivier Fourdan | 69e087caa4 | |
Olivier Fourdan | d7391f383d | |
Jacob Cherry | a5367face1 | |
Olivier Fourdan | 97ed0048e4 | |
Jeremy Huddleston Sequoia | 9d329a0fb1 | |
Jeremy Huddleston Sequoia | 839b49ac05 | |
Jeremy Huddleston Sequoia | 677eb6827b | |
Jeremy Huddleston Sequoia | 25035229b7 | |
Jeremy Huddleston Sequoia | 487286d472 | |
Jeremy Huddleston Sequoia | 6a83fb51b7 | |
Jeremy Huddleston Sequoia | a3ddcdd56c | |
Jeremy Huddleston Sequoia | 279bcbd9cf | |
Jeremy Huddleston Sequoia | fe89c70e47 | |
Jeremy Huddleston Sequoia | 41aed8f696 | |
Jeremy Huddleston Sequoia | c2750e1fab | |
Jeremy Huddleston Sequoia | f51b97b0de | |
Jeremy Huddleston Sequoia | 4b4500c48f | |
Jeremy Huddleston Sequoia | 39c0e1c0ab | |
Jeremy Huddleston Sequoia | 87f8fe1f74 | |
Jeremy Huddleston Sequoia | 94e4e17348 | |
Jeremy Huddleston Sequoia | fba421f700 | |
Jeremy Huddleston Sequoia | 318f8a4a8a | |
Jeremy Huddleston Sequoia | 72a39dccf9 | |
Jeremy Huddleston Sequoia | 7e28750358 | |
Jeremy Huddleston Sequoia | 85beee9885 | |
Jeremy Huddleston Sequoia | 4e892aa6e1 | |
Jeremy Huddleston Sequoia | c9a3b14c14 | |
Povilas Kanapickas | af17b5c499 | |
Peter Hutterer | 20c78f38a0 | |
Olivier Fourdan | dee2bb033e | |
Olivier Fourdan | ab76272a7d | |
Olivier Fourdan | a4095162ca | |
Olivier Fourdan | 1abab61dc2 | |
Olivier Fourdan | 7181792824 | |
Olivier Fourdan | c5c5322ad6 | |
Olivier Fourdan | ebdb2e2646 | |
Olivier Fourdan | b5e1f13681 | |
Povilas Kanapickas | 213129012b | |
Povilas Kanapickas | 30e11535af | |
Povilas Kanapickas | f682e0563f |
|
@ -29,6 +29,7 @@ pkg-config,\
|
|||
python3,\
|
||||
windowsdriproto,\
|
||||
xorgproto,\
|
||||
libdmx-devel,\
|
||||
libepoxy-devel,\
|
||||
libfontenc-devel,\
|
||||
libfreetype-devel,\
|
||||
|
@ -72,7 +73,7 @@ cache:
|
|||
- '%CYGWIN_ROOT%\home\%USERNAME%\.ccache'
|
||||
build_script:
|
||||
- SET PATH=%CYGWIN_ROOT%/bin
|
||||
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson setup --prefix=/usr -Dxv=false -Dxf86bigfont=true -Dxvfb=true build"'
|
||||
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson setup --prefix=/usr -Dxv=false -Dxf86bigfont=true -Ddmx=true -Dxephyr=true -Dxnest=true -Dxvfb=true -Dxwin=true -Dxorg=true -Dhal=false -Dudev=false -Dpciaccess=false -Dint10=false build"'
|
||||
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson configure build"'
|
||||
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; ninja -C build"'
|
||||
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; ccache -s"'
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
# gcc/clang or other packages, which might break the build with older commits
|
||||
# using the same tag.
|
||||
variables:
|
||||
UPSTREAM_REPO: xorg/xserver
|
||||
FDO_UPSTREAM_REPO: xorg/xserver
|
||||
FDO_DISTRIBUTION_VERSION: buster-slim
|
||||
FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} bash .gitlab-ci/debian-install.sh'
|
||||
FDO_DISTRIBUTION_TAG: "2021-01-19-git"
|
||||
FDO_DISTRIBUTION_TAG: "2021-07-09"
|
||||
|
||||
include:
|
||||
- project: 'freedesktop/ci-templates'
|
||||
|
@ -59,10 +59,21 @@ debian-buster:
|
|||
after_script:
|
||||
- ccache --show-stats
|
||||
|
||||
autotools:
|
||||
extends: .common-build-and-test
|
||||
script:
|
||||
- mkdir build/
|
||||
- cd build/
|
||||
- ../autogen.sh --prefix=/usr CFLAGS="-fno-common"
|
||||
- make -j${FDO_CI_CONCURRENT:-4} distcheck
|
||||
- PIGLIT_DIR=/root/piglit XTEST_DIR=/root/xts make -j${FDO_CI_CONCURRENT:-4} check
|
||||
- cd ..
|
||||
- .gitlab-ci/manpages-check
|
||||
|
||||
meson:
|
||||
extends: .common-build-and-test
|
||||
script:
|
||||
- meson -Dc_args="-fno-common" -Dprefix=/usr -Dxvfb=false -Dwerror=true $MESON_EXTRA_OPTIONS build/
|
||||
- meson -Dc_args="-fno-common" -Dprefix=/usr -Dxephyr=true -Dwerror=true $MESON_EXTRA_OPTIONS build/
|
||||
- ninja -j${FDO_CI_CONCURRENT:-4} -C build/ dist
|
||||
- PIGLIT_DIR=/root/piglit XTEST_DIR=/root/xts ninja -j${FDO_CI_CONCURRENT:-4} -C build/ test
|
||||
- .gitlab-ci/manpages-check
|
||||
|
@ -72,3 +83,9 @@ meson-noglamor:
|
|||
variables:
|
||||
MESON_EXTRA_OPTIONS: >
|
||||
-Dglamor=false
|
||||
|
||||
mingw-cross-build:
|
||||
extends: .common-build-and-test
|
||||
script:
|
||||
- meson --cross-file=.gitlab-ci/cross-i686-w64-mingw32.txt -Dglx=false -Dsecure-rpc=false -Dlisten_tcp=true build/
|
||||
- ninja -j${FDO_CI_CONCURRENT:-4} -C build/ install
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
[binaries]
|
||||
c = 'i686-w64-mingw32-gcc'
|
||||
cpp = 'i686-w64-mingw32-g++'
|
||||
ar = 'i686-w64-mingw32-ar'
|
||||
strip = 'i686-w64-mingw32-strip'
|
||||
pkgconfig = '/usr/local/bin/i686-w64-mingw32-pkg-config'
|
||||
windres = 'i686-w64-mingw32-windres'
|
||||
exe_wrapper = 'wine'
|
||||
|
||||
[properties]
|
||||
# Directory that contains 'bin', 'lib', etc for the toolchain
|
||||
root = '/usr/i686-w64-mingw32'
|
||||
# Directory that contains 'bin', 'lib', etc which have been cross-compiled
|
||||
sys_root = '/usr/i686-w64-mingw32'
|
||||
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
cpu_family = 'x86'
|
||||
cpu = 'i686'
|
||||
endian = 'little'
|
|
@ -0,0 +1,79 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -o xtrace
|
||||
|
||||
HOST=$1
|
||||
|
||||
# Debian's cross-pkg-config wrappers are broken for MinGW targets, since
|
||||
# dpkg-architecture doesn't know about MinGW target triplets.
|
||||
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=930492
|
||||
cat >/usr/local/bin/${HOST}-pkg-config <<EOF
|
||||
#!/bin/sh
|
||||
|
||||
PKG_CONFIG_SYSROOT_DIR=/usr/${HOST} PKG_CONFIG_LIBDIR=/usr/${HOST}/lib/pkgconfig:/usr/share/pkgconfig pkg-config \$@
|
||||
EOF
|
||||
chmod +x /usr/local/bin/${HOST}-pkg-config
|
||||
|
||||
# when cross-compiling, some autoconf tests cannot be run:
|
||||
|
||||
# --enable-malloc0returnsnull
|
||||
export xorg_cv_malloc0_returns_null=yes
|
||||
|
||||
build() {
|
||||
url=$1
|
||||
commit=$2
|
||||
config=$3
|
||||
|
||||
name=$(basename ${url} .git)
|
||||
|
||||
if [[ $commit =~ ^[[:xdigit:]]{1,}$ ]]
|
||||
then
|
||||
git clone ${url} ${name}
|
||||
git -C ${name} checkout ${commit}
|
||||
else
|
||||
git clone --depth 1 --branch ${commit:-master} --recurse-submodules -c advice.detachedHead=false ${url} ${name}
|
||||
fi
|
||||
|
||||
pushd ${name}
|
||||
NOCONFIGURE=1 ./autogen.sh || ./.bootstrap
|
||||
./configure ${config} --host=${HOST} --prefix= --with-sysroot=/usr/${HOST}/
|
||||
make -j$(nproc)
|
||||
DESTDIR=/usr/${HOST} make install
|
||||
|
||||
popd
|
||||
rm -rf ${OLDPWD}
|
||||
}
|
||||
|
||||
build 'https://gitlab.freedesktop.org/pixman/pixman.git' 'pixman-0.38.4'
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/pthread-stubs.git' '0.4'
|
||||
# we can't use the xorgproto pkgconfig files from /usr/share/pkgconfig, because
|
||||
# these would add -I/usr/include to CFLAGS, which breaks cross-compilation
|
||||
build 'https://gitlab.freedesktop.org/xorg/proto/xorgproto.git' 'xorgproto-2021.4.99.2' '--datadir=/lib'
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/libXau.git' 'libXau-1.0.9'
|
||||
build 'https://gitlab.freedesktop.org/xorg/proto/xcbproto.git' 'xcb-proto-1.14'
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/libxcb.git' 'libxcb-1.14'
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/libxtrans.git' 'xtrans-1.4.0'
|
||||
# the default value of keysymdefdir is taken from the includedir variable for
|
||||
# xproto, which isn't adjusted by pkg-config for the sysroot
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/libX11.git' 'libX11-1.6.9' "--with-keysymdefdir=/usr/${HOST}/include/X11"
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/libxkbfile.git' 'libxkbfile-1.1.0'
|
||||
# freetype needs an explicit --build to know it's cross-compiling
|
||||
# disable png as freetype tries to use libpng-config, even when cross-compiling
|
||||
build 'git://git.savannah.gnu.org/freetype/freetype2.git' 'VER-2-10-1' "--build=$(cc -dumpmachine) --with-png=no"
|
||||
build 'https://gitlab.freedesktop.org/xorg//font/util.git' 'font-util-1.3.2'
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/libfontenc.git' 'libfontenc-1.1.4'
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/libXfont.git' 'libXfont2-2.0.3'
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/libXdmcp.git' 'libXdmcp-1.1.3'
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/libXfixes.git' 'libXfixes-5.0.3'
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/libxcb-util.git' '0.4.0'
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/libxcb-image.git' '0.4.0'
|
||||
build 'https://gitlab.freedesktop.org/xorg/lib/libxcb-wm.git' '0.4.1'
|
||||
|
||||
# workaround xcb_windefs.h leaking all Windows API types into X server build
|
||||
# (some of which clash which types defined by Xmd.h) XXX: This is a bit of a
|
||||
# hack, as it makes this header depend on xorgproto. Maybe an upstreamable
|
||||
# fix would involve a macro defined in the X server (XFree86Server?
|
||||
# XCB_NO_WINAPI?), which makes xcb_windefs.h wrap things like XWinsock.h
|
||||
# does???
|
||||
sed -i s#winsock2#X11/Xwinsock# /usr/${HOST}/include/xcb/xcb_windefs.h
|
|
@ -25,7 +25,9 @@ apt-get install -y \
|
|||
build-essential \
|
||||
ca-certificates \
|
||||
ccache \
|
||||
dpkg-dev \
|
||||
flex \
|
||||
gcc-mingw-w64-i686 \
|
||||
git \
|
||||
libaudit-dev \
|
||||
libbsd-dev \
|
||||
|
@ -87,21 +89,40 @@ apt-get install -y \
|
|||
libxt-dev \
|
||||
libxtst-dev \
|
||||
libxv-dev \
|
||||
libz-mingw-w64-dev \
|
||||
mesa-common-dev \
|
||||
meson \
|
||||
mingw-w64-tools \
|
||||
nettle-dev \
|
||||
pkg-config \
|
||||
python3-mako \
|
||||
python3-numpy \
|
||||
python3-six \
|
||||
x11proto-dev \
|
||||
xfonts-utils \
|
||||
xkb-data \
|
||||
xtrans-dev \
|
||||
xutils-dev
|
||||
|
||||
.gitlab-ci/cross-prereqs-build.sh i686-w64-mingw32
|
||||
|
||||
cd /root
|
||||
|
||||
# xserver requires libxcvt
|
||||
git clone https://gitlab.freedesktop.org/xorg/lib//libxcvt.git --depth 1 --branch=libxcvt-0.1.0
|
||||
cd libxcvt
|
||||
meson _build
|
||||
ninja -C _build -j${FDO_CI_CONCURRENT:-4} install
|
||||
cd ..
|
||||
rm -rf libxcvt
|
||||
|
||||
# xserver requires xorgproto >= 2021.4.99.2 for XI 2.3.99.1
|
||||
git clone https://gitlab.freedesktop.org/xorg/proto/xorgproto.git --depth 1 --branch=xorgproto-2021.4.99.2
|
||||
pushd xorgproto
|
||||
./autogen.sh
|
||||
make -j${FDO_CI_CONCURRENT:-4} install
|
||||
popd
|
||||
rm -rf xorgproto
|
||||
|
||||
# weston 9.0 requires libwayland >= 1.18
|
||||
git clone https://gitlab.freedesktop.org/wayland/wayland.git --depth 1 --branch=1.18.0
|
||||
cd wayland
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
language: c
|
||||
cache:
|
||||
ccache: true
|
||||
directories:
|
||||
- $HOME/Library/Caches/Homebrew
|
||||
branches:
|
||||
except:
|
||||
- /appveyor.*/
|
||||
|
||||
os: osx
|
||||
osx_image: xcode9.2
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- env: TOOL=meson
|
||||
- env: TOOL=autotools
|
||||
|
||||
install:
|
||||
- brew update
|
||||
- HOMEBREW_NO_AUTO_UPDATE=1 brew install ccache meson
|
||||
|
||||
script:
|
||||
- ./test/scripts/build-travis-osx.sh $TOOL
|
||||
- ccache -s
|
||||
|
||||
before_cache:
|
||||
- brew cleanup
|
|
@ -0,0 +1,215 @@
|
|||
AUTOMAKE_OPTIONS=nostdinc
|
||||
|
||||
# Required for automake < 1.14
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
if COMPOSITE
|
||||
COMPOSITE_DIR=composite
|
||||
endif
|
||||
|
||||
if GLX
|
||||
GLX_DIR=glx
|
||||
endif
|
||||
|
||||
if DBE
|
||||
DBE_DIR=dbe
|
||||
endif
|
||||
|
||||
if RECORD
|
||||
RECORD_DIR=record
|
||||
endif
|
||||
|
||||
if DRI3
|
||||
DRI3_DIR=dri3
|
||||
endif
|
||||
|
||||
if PRESENT
|
||||
PRESENT_DIR=present
|
||||
endif
|
||||
|
||||
if PSEUDORAMIX
|
||||
PSEUDORAMIX_DIR=pseudoramiX
|
||||
endif
|
||||
|
||||
if GLAMOR
|
||||
GLAMOR_DIR=glamor
|
||||
endif
|
||||
|
||||
SUBDIRS = \
|
||||
doc \
|
||||
man \
|
||||
include \
|
||||
dix \
|
||||
fb \
|
||||
mi \
|
||||
Xext \
|
||||
miext \
|
||||
os \
|
||||
randr \
|
||||
render \
|
||||
Xi \
|
||||
xkb \
|
||||
$(PSEUDORAMIX_DIR) \
|
||||
$(DBE_DIR) \
|
||||
$(RECORD_DIR) \
|
||||
xfixes \
|
||||
damageext \
|
||||
$(COMPOSITE_DIR) \
|
||||
$(GLX_DIR) \
|
||||
$(PRESENT_DIR) \
|
||||
$(DRI3_DIR) \
|
||||
exa \
|
||||
$(GLAMOR_DIR) \
|
||||
config \
|
||||
hw \
|
||||
test
|
||||
|
||||
if XORG
|
||||
aclocaldir = $(datadir)/aclocal
|
||||
aclocal_DATA = xorg-server.m4
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = xorg-server.pc
|
||||
endif
|
||||
|
||||
EXTRA_DIST = xorg-server.pc.in xorg-server.m4 autogen.sh README.md
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS=\
|
||||
--with-xkb-path=$(XKB_BASE_DIRECTORY) \
|
||||
--with-xkb-bin-directory=$(XKB_BIN_DIRECTORY) \
|
||||
--with-xkb-output='$${datadir}/X11/xkb/compiled'
|
||||
|
||||
.PHONY: ChangeLog INSTALL
|
||||
|
||||
INSTALL:
|
||||
$(INSTALL_CMD)
|
||||
|
||||
ChangeLog:
|
||||
$(CHANGELOG_CMD)
|
||||
|
||||
dist-hook: ChangeLog INSTALL
|
||||
|
||||
DIST_SUBDIRS = \
|
||||
doc \
|
||||
man \
|
||||
include \
|
||||
dix \
|
||||
fb \
|
||||
mi \
|
||||
Xext \
|
||||
miext \
|
||||
os \
|
||||
pseudoramiX \
|
||||
randr \
|
||||
render \
|
||||
Xi \
|
||||
xkb \
|
||||
dbe \
|
||||
record \
|
||||
xfixes \
|
||||
damageext \
|
||||
composite \
|
||||
glx \
|
||||
exa \
|
||||
glamor \
|
||||
config \
|
||||
dri3 \
|
||||
present \
|
||||
hw \
|
||||
test
|
||||
|
||||
# gross hack
|
||||
relink: all
|
||||
$(AM_V_at)$(MAKE) -C hw relink
|
||||
|
||||
install-headers: Makefile
|
||||
+find . -name Makefile | while read m; do \
|
||||
if grep -q install-sdkHEADERS $$m; then \
|
||||
(cd `dirname "$$m"` && make install-sdkHEADERS) \
|
||||
fi \
|
||||
done
|
||||
|
||||
distcheck-hook:
|
||||
cd $(srcdir) && \
|
||||
meson setup _distcheck_build && \
|
||||
meson configure _distcheck_build && \
|
||||
ninja -C _distcheck_build && \
|
||||
rm -rf _distcheck_build && \
|
||||
cd -
|
||||
|
||||
EXTRA_DIST += \
|
||||
meson_options.txt \
|
||||
include/xorg-config.h.meson.in \
|
||||
include/xwin-config.h.meson.in \
|
||||
hw/xfree86/loader/symbol-test.c \
|
||||
composite/meson.build \
|
||||
config/meson.build \
|
||||
damageext/meson.build \
|
||||
dbe/meson.build \
|
||||
dix/meson.build \
|
||||
dri3/meson.build \
|
||||
exa/meson.build \
|
||||
fb/meson.build \
|
||||
glamor/meson.build \
|
||||
glx/meson.build \
|
||||
hw/dmx/config/meson.build \
|
||||
hw/dmx/examples/meson.build \
|
||||
hw/dmx/glxProxy/meson.build \
|
||||
hw/dmx/input/meson.build \
|
||||
hw/dmx/meson.build \
|
||||
hw/kdrive/ephyr/meson.build \
|
||||
hw/kdrive/meson.build \
|
||||
hw/kdrive/src/meson.build \
|
||||
hw/meson.build \
|
||||
hw/vfb/meson.build \
|
||||
hw/xfree86/common/meson.build \
|
||||
hw/xfree86/ddc/meson.build \
|
||||
hw/xfree86/dixmods/meson.build \
|
||||
hw/xfree86/dri2/meson.build \
|
||||
hw/xfree86/dri/meson.build \
|
||||
hw/xfree86/drivers/modesetting/meson.build \
|
||||
hw/xfree86/exa/meson.build \
|
||||
hw/xfree86/fbdevhw/meson.build \
|
||||
hw/xfree86/glamor_egl/meson.build \
|
||||
hw/xfree86/i2c/meson.build \
|
||||
hw/xfree86/int10/meson.build \
|
||||
hw/xfree86/loader/meson.build \
|
||||
hw/xfree86/meson.build \
|
||||
hw/xfree86/modes/meson.build \
|
||||
hw/xfree86/os-support/meson.build \
|
||||
hw/xfree86/parser/meson.build \
|
||||
hw/xfree86/ramdac/meson.build \
|
||||
hw/xfree86/shadowfb/meson.build \
|
||||
hw/xfree86/vgahw/meson.build \
|
||||
hw/xfree86/x86emu/meson.build \
|
||||
hw/xfree86/xkb/meson.build \
|
||||
hw/xnest/meson.build \
|
||||
hw/xquartz/meson.build \
|
||||
hw/xwayland/meson.build \
|
||||
hw/xwin/dri/meson.build \
|
||||
hw/xwin/glx/meson.build \
|
||||
hw/xwin/meson.build \
|
||||
hw/xwin/winclipboard/meson.build \
|
||||
include/meson.build \
|
||||
meson.build \
|
||||
miext/damage/meson.build \
|
||||
miext/shadow/meson.build \
|
||||
miext/sync/meson.build \
|
||||
mi/meson.build \
|
||||
os/meson.build \
|
||||
present/meson.build \
|
||||
pseudoramiX/meson.build \
|
||||
randr/meson.build \
|
||||
record/meson.build \
|
||||
render/meson.build \
|
||||
test/bigreq/meson.build \
|
||||
test/bigreq/request-length.c \
|
||||
test/meson.build \
|
||||
test/sync/meson.build \
|
||||
test/sync/sync.c \
|
||||
Xext/meson.build \
|
||||
xfixes/meson.build \
|
||||
Xi/meson.build \
|
||||
xkb/meson.build
|
||||
|
||||
DISTCLEANFILES = buildDateTime.h
|
|
@ -0,0 +1,120 @@
|
|||
noinst_LTLIBRARIES = libXext.la libXvidmode.la libhashtable.la
|
||||
|
||||
AM_CFLAGS = $(DIX_CFLAGS)
|
||||
|
||||
if XORG
|
||||
sdk_HEADERS = xvdix.h xvmcext.h geext.h geint.h shmint.h syncsdk.h
|
||||
endif
|
||||
|
||||
# Sources always included in libXextbuiltin.la, libXext.la
|
||||
BUILTIN_SRCS = \
|
||||
bigreq.c \
|
||||
geext.c \
|
||||
shape.c \
|
||||
sleepuntil.c \
|
||||
sleepuntil.h \
|
||||
sync.c \
|
||||
syncsdk.h \
|
||||
syncsrv.h \
|
||||
xcmisc.c \
|
||||
xtest.c
|
||||
BUILTIN_LIBS =
|
||||
|
||||
# Optional sources included if extension enabled by configure.ac rules
|
||||
|
||||
# MIT Shared Memory extension
|
||||
MITSHM_SRCS = shm.c shmint.h
|
||||
if MITSHM
|
||||
BUILTIN_SRCS += $(MITSHM_SRCS)
|
||||
endif
|
||||
|
||||
# XVideo extension
|
||||
XV_SRCS = xvmain.c xvdisp.c xvmc.c xvdix.h xvmcext.h xvdisp.h
|
||||
if XV
|
||||
BUILTIN_SRCS += $(XV_SRCS)
|
||||
endif
|
||||
|
||||
# XResource extension: lets clients get data about per-client resource usage
|
||||
RES_SRCS = xres.c
|
||||
if RES
|
||||
BUILTIN_SRCS += $(RES_SRCS)
|
||||
endif
|
||||
|
||||
# MIT ScreenSaver extension
|
||||
SCREENSAVER_SRCS = saver.c
|
||||
if SCREENSAVER
|
||||
BUILTIN_SRCS += $(SCREENSAVER_SRCS)
|
||||
endif
|
||||
|
||||
# Xinerama extension: making multiple video devices act as one virtual screen
|
||||
XINERAMA_SRCS = panoramiX.c panoramiX.h panoramiXh.h panoramiXsrv.h panoramiXprocs.c panoramiXSwap.c
|
||||
if XINERAMA
|
||||
BUILTIN_SRCS += $(XINERAMA_SRCS)
|
||||
if XORG
|
||||
sdk_HEADERS += panoramiXsrv.h panoramiX.h
|
||||
endif
|
||||
endif
|
||||
|
||||
# X-ACE extension: provides hooks for building security policy extensions
|
||||
# like XC-Security, X-SELinux & XTSol
|
||||
XACE_SRCS = xace.c xace.h xacestr.h
|
||||
if XACE
|
||||
BUILTIN_SRCS += $(XACE_SRCS)
|
||||
if XORG
|
||||
sdk_HEADERS += xace.h xacestr.h
|
||||
endif
|
||||
endif
|
||||
|
||||
# SELinux extension: provides SELinux policy support for X objects
|
||||
# requires X-ACE extension
|
||||
XSELINUX_SRCS = xselinux_ext.c xselinux_hooks.c xselinux_label.c xselinux.h xselinuxint.h
|
||||
if XSELINUX
|
||||
BUILTIN_SRCS += $(XSELINUX_SRCS)
|
||||
BUILTIN_LIBS += $(SELINUX_LIBS)
|
||||
endif
|
||||
|
||||
# Security extension: multi-level security to protect clients from each other
|
||||
XCSECURITY_SRCS = security.c securitysrv.h
|
||||
if XCSECURITY
|
||||
BUILTIN_SRCS += $(XCSECURITY_SRCS)
|
||||
endif
|
||||
|
||||
# XF86 Big Font extension
|
||||
BIGFONT_SRCS = xf86bigfont.c xf86bigfontsrv.h
|
||||
if XF86BIGFONT
|
||||
BUILTIN_SRCS += $(BIGFONT_SRCS)
|
||||
endif
|
||||
|
||||
# DPMS extension
|
||||
DPMS_SRCS = dpms.c dpmsproc.h
|
||||
if DPMSExtension
|
||||
BUILTIN_SRCS += $(DPMS_SRCS)
|
||||
endif
|
||||
|
||||
# Now take all of the above, mix well, bake for 10 minutes and get libXext*.la
|
||||
|
||||
libXext_la_SOURCES = $(BUILTIN_SRCS)
|
||||
libXext_la_LIBADD = $(BUILTIN_LIBS)
|
||||
if RES
|
||||
libXext_la_LIBADD += libhashtable.la
|
||||
endif
|
||||
|
||||
# XVidMode extension
|
||||
libXvidmode_la_SOURCES = vidmode.c
|
||||
|
||||
#Hashtable
|
||||
libhashtable_la_SOURCES = hashtable.c hashtable.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(MITSHM_SRCS) \
|
||||
$(XV_SRCS) \
|
||||
$(RES_SRCS) \
|
||||
$(SCREENSAVER_SRCS) \
|
||||
$(XACE_SRCS) \
|
||||
$(XCSECURITY_SRCS) \
|
||||
$(XSELINUX_SRCS) \
|
||||
$(XINERAMA_SRCS) \
|
||||
$(BIGFONT_SRCS) \
|
||||
$(DPMS_SRCS) \
|
||||
$(GE_SRCS)
|
||||
|
|
@ -138,9 +138,15 @@ ProcGEDispatch(ClientPtr client)
|
|||
static int _X_COLD
|
||||
SProcGEDispatch(ClientPtr client)
|
||||
{
|
||||
GEClientInfoPtr pGEClient = GEGetClient(client);
|
||||
|
||||
REQUEST(xGEReq);
|
||||
if (stuff->ReqType >= GENumberRequests)
|
||||
|
||||
if (pGEClient->major_version >= ARRAY_SIZE(version_requests))
|
||||
return BadRequest;
|
||||
if (stuff->ReqType > version_requests[pGEClient->major_version])
|
||||
return BadRequest;
|
||||
|
||||
return (*SProcGEVector[stuff->ReqType]) (client);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,3 +73,7 @@ libxserver_xext_vidmode = static_library('libxserver_xext_vidmode',
|
|||
include_directories: inc,
|
||||
dependencies: common_dep,
|
||||
)
|
||||
|
||||
if build_xorg
|
||||
install_data(hdrs_xext, install_dir: xorgsdkdir)
|
||||
endif
|
||||
|
|
|
@ -37,8 +37,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#define USE_SEL offsetof(SELinuxSubjectRec, sel_use_sid)
|
||||
|
||||
typedef struct {
|
||||
security_context_t octx;
|
||||
security_context_t dctx;
|
||||
char *octx;
|
||||
char *dctx;
|
||||
CARD32 octx_len;
|
||||
CARD32 dctx_len;
|
||||
CARD32 id;
|
||||
|
@ -48,10 +48,10 @@ typedef struct {
|
|||
* Extension Dispatch
|
||||
*/
|
||||
|
||||
static security_context_t
|
||||
static char *
|
||||
SELinuxCopyContext(char *ptr, unsigned len)
|
||||
{
|
||||
security_context_t copy = malloc(len + 1);
|
||||
char *copy = malloc(len + 1);
|
||||
|
||||
if (!copy)
|
||||
return NULL;
|
||||
|
@ -84,7 +84,7 @@ static int
|
|||
SELinuxSendContextReply(ClientPtr client, security_id_t sid)
|
||||
{
|
||||
SELinuxGetContextReply rep;
|
||||
security_context_t ctx = NULL;
|
||||
char *ctx = NULL;
|
||||
int len = 0;
|
||||
|
||||
if (sid) {
|
||||
|
@ -117,7 +117,7 @@ ProcSELinuxSetCreateContext(ClientPtr client, unsigned offset)
|
|||
{
|
||||
PrivateRec **privPtr = &client->devPrivates;
|
||||
security_id_t *pSid;
|
||||
security_context_t ctx = NULL;
|
||||
char *ctx = NULL;
|
||||
char *ptr;
|
||||
int rc;
|
||||
|
||||
|
@ -165,7 +165,7 @@ ProcSELinuxGetCreateContext(ClientPtr client, unsigned offset)
|
|||
static int
|
||||
ProcSELinuxSetDeviceContext(ClientPtr client)
|
||||
{
|
||||
security_context_t ctx;
|
||||
char *ctx;
|
||||
security_id_t sid;
|
||||
DeviceIntPtr dev;
|
||||
SELinuxSubjectRec *subj;
|
||||
|
|
|
@ -114,7 +114,7 @@ SELinuxLabelClient(ClientPtr client)
|
|||
int fd = XaceGetConnectionNumber(client);
|
||||
SELinuxSubjectRec *subj;
|
||||
SELinuxObjectRec *obj;
|
||||
security_context_t ctx;
|
||||
char *ctx;
|
||||
|
||||
subj = dixLookupPrivate(&client->devPrivates, subjectKey);
|
||||
obj = dixLookupPrivate(&client->devPrivates, objectKey);
|
||||
|
@ -169,7 +169,7 @@ SELinuxLabelInitial(void)
|
|||
XaceScreenAccessRec srec;
|
||||
SELinuxSubjectRec *subj;
|
||||
SELinuxObjectRec *obj;
|
||||
security_context_t ctx;
|
||||
char *ctx;
|
||||
void *unused;
|
||||
|
||||
/* Do the serverClient */
|
||||
|
@ -773,7 +773,7 @@ SELinuxResourceState(CallbackListPtr *pcbl, void *unused, void *calldata)
|
|||
subj = dixLookupPrivate(&wClient(pWin)->devPrivates, subjectKey);
|
||||
|
||||
if (subj->sid) {
|
||||
security_context_t ctx;
|
||||
char *ctx;
|
||||
int rc = avc_sid_to_context_raw(subj->sid, &ctx);
|
||||
|
||||
if (rc < 0)
|
||||
|
@ -791,7 +791,7 @@ SELinuxResourceState(CallbackListPtr *pcbl, void *unused, void *calldata)
|
|||
obj = dixLookupPrivate(&pWin->devPrivates, objectKey);
|
||||
|
||||
if (obj->sid) {
|
||||
security_context_t ctx;
|
||||
char *ctx;
|
||||
int rc = avc_sid_to_context_raw(obj->sid, &ctx);
|
||||
|
||||
if (rc < 0)
|
||||
|
@ -847,7 +847,7 @@ void
|
|||
SELinuxFlaskInit(void)
|
||||
{
|
||||
struct selinux_opt avc_option = { AVC_OPT_SETENFORCE, (char *) 0 };
|
||||
security_context_t ctx;
|
||||
char *ctx;
|
||||
int ret = TRUE;
|
||||
|
||||
switch (selinuxEnforcingState) {
|
||||
|
|
|
@ -97,7 +97,7 @@ static int
|
|||
SELinuxAtomToSIDLookup(Atom atom, SELinuxObjectRec * obj, int map, int polymap)
|
||||
{
|
||||
const char *name = NameForAtom(atom);
|
||||
security_context_t ctx;
|
||||
char *ctx;
|
||||
int rc = Success;
|
||||
|
||||
obj->poly = 1;
|
||||
|
@ -255,7 +255,7 @@ SELinuxEventToSID(unsigned type, security_id_t sid_of_window,
|
|||
{
|
||||
const char *name = LookupEventName(type);
|
||||
security_id_t sid;
|
||||
security_context_t ctx;
|
||||
char *ctx;
|
||||
|
||||
type &= 127;
|
||||
|
||||
|
@ -291,7 +291,7 @@ SELinuxEventToSID(unsigned type, security_id_t sid_of_window,
|
|||
int
|
||||
SELinuxExtensionToSID(const char *name, security_id_t * sid_rtn)
|
||||
{
|
||||
security_context_t ctx;
|
||||
char *ctx;
|
||||
|
||||
/* Look in the mappings of extension names to contexts */
|
||||
if (selabel_lookup_raw(label_hnd, &ctx, name, SELABEL_X_EXT) < 0) {
|
||||
|
@ -347,10 +347,10 @@ SELinuxTypeToClass(RESTYPE type)
|
|||
return (security_class_t) (unsigned long) tmp;
|
||||
}
|
||||
|
||||
security_context_t
|
||||
char *
|
||||
SELinuxDefaultClientLabel(void)
|
||||
{
|
||||
security_context_t ctx;
|
||||
char *ctx;
|
||||
|
||||
if (selabel_lookup_raw(label_hnd, &ctx, "remote", SELABEL_X_CLIENT) < 0)
|
||||
FatalError("SELinux: failed to look up remote-client context\n");
|
||||
|
|
|
@ -99,7 +99,7 @@ int
|
|||
|
||||
security_class_t SELinuxTypeToClass(RESTYPE type);
|
||||
|
||||
security_context_t SELinuxDefaultClientLabel(void);
|
||||
char *SELinuxDefaultClientLabel(void);
|
||||
|
||||
void
|
||||
SELinuxLabelInit(void);
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
noinst_LTLIBRARIES = libXi.la libXistubs.la
|
||||
|
||||
AM_CFLAGS = $(DIX_CFLAGS)
|
||||
|
||||
libXi_la_SOURCES = \
|
||||
allowev.c \
|
||||
allowev.h \
|
||||
chgdctl.c \
|
||||
chgdctl.h \
|
||||
chgfctl.c \
|
||||
chgfctl.h \
|
||||
chgkbd.c \
|
||||
chgkbd.h \
|
||||
chgkmap.c \
|
||||
chgkmap.h \
|
||||
chgprop.c \
|
||||
chgprop.h \
|
||||
chgptr.c \
|
||||
chgptr.h \
|
||||
closedev.c \
|
||||
closedev.h \
|
||||
devbell.c \
|
||||
devbell.h \
|
||||
exevents.c \
|
||||
exglobals.h \
|
||||
extinit.c \
|
||||
getbmap.c \
|
||||
getbmap.h \
|
||||
getdctl.c \
|
||||
getdctl.h \
|
||||
getfctl.c \
|
||||
getfctl.h \
|
||||
getfocus.c \
|
||||
getfocus.h \
|
||||
getkmap.c \
|
||||
getkmap.h \
|
||||
getmmap.c \
|
||||
getmmap.h \
|
||||
getprop.c \
|
||||
getprop.h \
|
||||
getselev.c \
|
||||
getselev.h \
|
||||
getvers.c \
|
||||
getvers.h \
|
||||
grabdev.c \
|
||||
grabdev.h \
|
||||
grabdevb.c \
|
||||
grabdevb.h \
|
||||
grabdevk.c \
|
||||
grabdevk.h \
|
||||
gtmotion.c \
|
||||
gtmotion.h \
|
||||
listdev.c \
|
||||
listdev.h \
|
||||
opendev.c \
|
||||
opendev.h \
|
||||
queryst.c \
|
||||
queryst.h \
|
||||
selectev.c \
|
||||
selectev.h \
|
||||
sendexev.c \
|
||||
sendexev.h \
|
||||
setbmap.c \
|
||||
setbmap.h \
|
||||
setdval.c \
|
||||
setdval.h \
|
||||
setfocus.c \
|
||||
setfocus.h \
|
||||
setmmap.c \
|
||||
setmmap.h \
|
||||
setmode.c \
|
||||
setmode.h \
|
||||
ungrdev.c \
|
||||
ungrdev.h \
|
||||
ungrdevb.c \
|
||||
ungrdevb.h \
|
||||
ungrdevk.c \
|
||||
ungrdevk.h \
|
||||
xiallowev.c \
|
||||
xiallowev.h \
|
||||
xibarriers.c \
|
||||
xibarriers.h \
|
||||
xichangecursor.c \
|
||||
xichangecursor.h \
|
||||
xichangehierarchy.c \
|
||||
xichangehierarchy.h \
|
||||
xigetclientpointer.c \
|
||||
xigetclientpointer.h \
|
||||
xigrabdev.c \
|
||||
xigrabdev.h \
|
||||
xipassivegrab.h \
|
||||
xipassivegrab.c \
|
||||
xiproperty.c \
|
||||
xiproperty.h \
|
||||
xiquerydevice.c \
|
||||
xiquerydevice.h \
|
||||
xiquerypointer.c \
|
||||
xiquerypointer.h \
|
||||
xiqueryversion.c \
|
||||
xiqueryversion.h \
|
||||
xiselectev.c \
|
||||
xiselectev.h \
|
||||
xisetclientpointer.c \
|
||||
xisetclientpointer.h \
|
||||
xisetdevfocus.c \
|
||||
xisetdevfocus.h \
|
||||
xiwarppointer.c \
|
||||
xiwarppointer.h
|
||||
|
||||
libXistubs_la_SOURCES = \
|
||||
stubs.c
|
268
Xi/exevents.c
268
Xi/exevents.c
|
@ -95,6 +95,7 @@ SOFTWARE.
|
|||
#include "exevents.h"
|
||||
#include "extnsionst.h"
|
||||
#include "exglobals.h"
|
||||
#include "eventstr.h"
|
||||
#include "dixevents.h" /* DeliverFocusedEvent */
|
||||
#include "dixgrabs.h" /* CreateGrab() */
|
||||
#include "scrnintstr.h"
|
||||
|
@ -168,6 +169,49 @@ IsTouchEvent(InternalEvent *event)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
Bool
|
||||
IsGestureEvent(InternalEvent *event)
|
||||
{
|
||||
switch (event->any.type) {
|
||||
case ET_GesturePinchBegin:
|
||||
case ET_GesturePinchUpdate:
|
||||
case ET_GesturePinchEnd:
|
||||
case ET_GestureSwipeBegin:
|
||||
case ET_GestureSwipeUpdate:
|
||||
case ET_GestureSwipeEnd:
|
||||
return TRUE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool
|
||||
IsGestureBeginEvent(InternalEvent *event)
|
||||
{
|
||||
switch (event->any.type) {
|
||||
case ET_GesturePinchBegin:
|
||||
case ET_GestureSwipeBegin:
|
||||
return TRUE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool
|
||||
IsGestureEndEvent(InternalEvent *event)
|
||||
{
|
||||
switch (event->any.type) {
|
||||
case ET_GesturePinchEnd:
|
||||
case ET_GestureSwipeEnd:
|
||||
return TRUE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the device matching the deviceid of the device set in the event, or
|
||||
* NULL if the event is not an XInput event.
|
||||
|
@ -647,6 +691,25 @@ DeepCopyPointerClasses(DeviceIntPtr from, DeviceIntPtr to)
|
|||
/* Don't remove touch class if from->touch is non-existent. The to device
|
||||
* may have an active touch grab, so we need to keep the touch class record
|
||||
* around. */
|
||||
|
||||
if (from->gesture) {
|
||||
if (!to->gesture) {
|
||||
classes = to->unused_classes;
|
||||
to->gesture = classes->gesture;
|
||||
if (!to->gesture) {
|
||||
if (!InitGestureClassDeviceStruct(to, from->gesture->max_touches))
|
||||
FatalError("[Xi] no memory for class shift.\n");
|
||||
}
|
||||
else
|
||||
classes->gesture = NULL;
|
||||
}
|
||||
|
||||
to->gesture->sourceid = from->gesture->sourceid;
|
||||
/* to->gesture->gesture is separate on the master, don't copy */
|
||||
}
|
||||
/* Don't remove gesture class if from->gesture is non-existent. The to device
|
||||
* may have an active gesture grab, so we need to keep the gesture class record
|
||||
* around. */
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1292,21 +1355,13 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
|
|||
int rc;
|
||||
InputClients *iclients = NULL;
|
||||
*mask = NULL;
|
||||
*grab = NULL;
|
||||
|
||||
if (listener->type == TOUCH_LISTENER_GRAB ||
|
||||
listener->type == TOUCH_LISTENER_POINTER_GRAB) {
|
||||
*grab = listener->grab;
|
||||
|
||||
BUG_RETURN_VAL(!*grab, FALSE);
|
||||
}
|
||||
else if (ti->emulate_pointer && dev->deviceGrab.grab &&
|
||||
!dev->deviceGrab.fromPassiveGrab) {
|
||||
/* There may be an active pointer grab on the device */
|
||||
*grab = dev->deviceGrab.grab;
|
||||
}
|
||||
|
||||
if (*grab) {
|
||||
*client = rClient(*grab);
|
||||
*win = (*grab)->window;
|
||||
*mask = (*grab)->xi2mask;
|
||||
|
@ -1363,6 +1418,8 @@ RetrieveTouchDeliveryData(DeviceIntPtr dev, TouchPointInfoPtr ti,
|
|||
/* if owner selected, oclients is NULL */
|
||||
*client = oclients ? rClient(oclients) : wClient(*win);
|
||||
}
|
||||
|
||||
*grab = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -1379,6 +1436,16 @@ DeliverTouchEmulatedEvent(DeviceIntPtr dev, TouchPointInfoPtr ti,
|
|||
int nevents;
|
||||
DeviceIntPtr kbd;
|
||||
|
||||
/* There may be a pointer grab on the device */
|
||||
if (!grab) {
|
||||
grab = dev->deviceGrab.grab;
|
||||
if (grab) {
|
||||
win = grab->window;
|
||||
xi2mask = grab->xi2mask;
|
||||
client = rClient(grab);
|
||||
}
|
||||
}
|
||||
|
||||
/* We don't deliver pointer events to non-owners */
|
||||
if (!TouchResourceIsOwner(ti, listener->listener))
|
||||
return !Success;
|
||||
|
@ -1676,6 +1743,72 @@ ProcessBarrierEvent(InternalEvent *e, DeviceIntPtr dev)
|
|||
free(ev);
|
||||
}
|
||||
|
||||
static BOOL
|
||||
IsAnotherGestureActiveOnMaster(DeviceIntPtr dev, InternalEvent* ev)
|
||||
{
|
||||
GestureClassPtr g = dev->gesture;
|
||||
if (g->gesture.active && g->gesture.sourceid != ev->gesture_event.sourceid) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes and delivers a Gesture{Pinch,Swipe}{Begin,Update,End}.
|
||||
*
|
||||
* Due to having rather different delivery semantics (see the Xi 2.4 protocol
|
||||
* spec for more information), this implements its own grab and event-selection
|
||||
* delivery logic.
|
||||
*/
|
||||
void
|
||||
ProcessGestureEvent(InternalEvent *ev, DeviceIntPtr dev)
|
||||
{
|
||||
GestureInfoPtr gi;
|
||||
DeviceIntPtr kbd;
|
||||
Bool deactivateGestureGrab = FALSE;
|
||||
Bool delivered = FALSE;
|
||||
|
||||
if (!dev->gesture)
|
||||
return;
|
||||
|
||||
if (IsMaster(dev) && IsAnotherGestureActiveOnMaster(dev, ev))
|
||||
return;
|
||||
|
||||
if (IsGestureBeginEvent(ev))
|
||||
gi = GestureBeginGesture(dev, ev);
|
||||
else
|
||||
gi = GestureFindActiveByEventType(dev, ev->any.type);
|
||||
|
||||
if (!gi) {
|
||||
/* This may happen if gesture is no longer active or was never started. */
|
||||
return;
|
||||
}
|
||||
|
||||
kbd = GetMaster(dev, KEYBOARD_OR_FLOAT);
|
||||
event_set_state_gesture(kbd, &ev->gesture_event);
|
||||
|
||||
if (IsGestureBeginEvent(ev))
|
||||
GestureSetupListener(dev, gi, ev);
|
||||
|
||||
if (IsGestureEndEvent(ev) &&
|
||||
dev->deviceGrab.grab &&
|
||||
dev->deviceGrab.fromPassiveGrab &&
|
||||
GrabIsGestureGrab(dev->deviceGrab.grab))
|
||||
deactivateGestureGrab = TRUE;
|
||||
|
||||
delivered = DeliverGestureEventToOwner(dev, gi, ev);
|
||||
|
||||
if (delivered && !deactivateGestureGrab &&
|
||||
(IsGestureBeginEvent(ev) || IsGestureEndEvent(ev)))
|
||||
FreezeThisEventIfNeededForSyncGrab(dev, ev);
|
||||
|
||||
if (IsGestureEndEvent(ev))
|
||||
GestureEndGesture(gi);
|
||||
|
||||
if (deactivateGestureGrab)
|
||||
(*dev->deviceGrab.DeactivateGrab) (dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process DeviceEvents and DeviceChangedEvents.
|
||||
*/
|
||||
|
@ -1870,6 +2003,14 @@ ProcessOtherEvent(InternalEvent *ev, DeviceIntPtr device)
|
|||
case ET_BarrierLeave:
|
||||
ProcessBarrierEvent(ev, device);
|
||||
break;
|
||||
case ET_GesturePinchBegin:
|
||||
case ET_GesturePinchUpdate:
|
||||
case ET_GesturePinchEnd:
|
||||
case ET_GestureSwipeBegin:
|
||||
case ET_GestureSwipeUpdate:
|
||||
case ET_GestureSwipeEnd:
|
||||
ProcessGestureEvent(ev, device);
|
||||
break;
|
||||
default:
|
||||
ProcessDeviceEvent(ev, device);
|
||||
break;
|
||||
|
@ -2074,6 +2215,111 @@ DeliverTouchEvents(DeviceIntPtr dev, TouchPointInfoPtr ti,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to deliver a gesture event to the given client.
|
||||
*/
|
||||
static Bool
|
||||
DeliverOneGestureEvent(ClientPtr client, DeviceIntPtr dev, GestureInfoPtr gi,
|
||||
GrabPtr grab, WindowPtr win, InternalEvent *ev)
|
||||
{
|
||||
int err;
|
||||
xEvent *xi2;
|
||||
Mask filter;
|
||||
Window child = DeepestSpriteWin(&gi->sprite)->drawable.id;
|
||||
|
||||
/* If we fail here, we're going to leave a client hanging. */
|
||||
err = EventToXI2(ev, &xi2);
|
||||
if (err != Success)
|
||||
FatalError("[Xi] %s: XI2 conversion failed in %s"
|
||||
" (%d)\n", dev->name, __func__, err);
|
||||
|
||||
FixUpEventFromWindow(&gi->sprite, xi2, win, child, FALSE);
|
||||
filter = GetEventFilter(dev, xi2);
|
||||
if (XaceHook(XACE_RECEIVE_ACCESS, client, win, xi2, 1) != Success)
|
||||
return FALSE;
|
||||
err = TryClientEvents(client, dev, xi2, 1, filter, filter, NullGrab);
|
||||
free(xi2);
|
||||
|
||||
/* Returning the value from TryClientEvents isn't useful, since all our
|
||||
* resource-gone cleanups will update the delivery list anyway. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a gesture event and a potential listener, retrieve info needed for processing the event.
|
||||
*
|
||||
* @param dev The device generating the gesture event.
|
||||
* @param ev The gesture event to process.
|
||||
* @param listener The gesture event listener that may receive the gesture event.
|
||||
* @param[out] client The client that should receive the gesture event.
|
||||
* @param[out] win The window to deliver the event on.
|
||||
* @param[out] grab The grab to deliver the event through, if any.
|
||||
* @return TRUE if an event should be delivered to the listener, FALSE
|
||||
* otherwise.
|
||||
*/
|
||||
static Bool
|
||||
RetrieveGestureDeliveryData(DeviceIntPtr dev, InternalEvent *ev, GestureListener* listener,
|
||||
ClientPtr *client, WindowPtr *win, GrabPtr *grab)
|
||||
{
|
||||
int rc;
|
||||
int evtype;
|
||||
InputClients *iclients = NULL;
|
||||
*grab = NULL;
|
||||
|
||||
if (listener->type == GESTURE_LISTENER_GRAB ||
|
||||
listener->type == GESTURE_LISTENER_NONGESTURE_GRAB) {
|
||||
*grab = listener->grab;
|
||||
|
||||
BUG_RETURN_VAL(!*grab, FALSE);
|
||||
|
||||
*client = rClient(*grab);
|
||||
*win = (*grab)->window;
|
||||
}
|
||||
else {
|
||||
rc = dixLookupResourceByType((void **) win, listener->listener, listener->resource_type,
|
||||
serverClient, DixSendAccess);
|
||||
if (rc != Success)
|
||||
return FALSE;
|
||||
|
||||
/* note that we only will have XI2 listeners as
|
||||
listener->type == GESTURE_LISTENER_REGULAR */
|
||||
evtype = GetXI2Type(ev->any.type);
|
||||
|
||||
nt_list_for_each_entry(iclients, wOtherInputMasks(*win)->inputClients, next)
|
||||
if (xi2mask_isset(iclients->xi2mask, dev, evtype))
|
||||
break;
|
||||
|
||||
BUG_RETURN_VAL(!iclients, FALSE);
|
||||
|
||||
*client = rClient(iclients);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers a gesture to the owner, if possible and needed. Returns whether
|
||||
* an event was delivered.
|
||||
*/
|
||||
Bool
|
||||
DeliverGestureEventToOwner(DeviceIntPtr dev, GestureInfoPtr gi, InternalEvent *ev)
|
||||
{
|
||||
GrabPtr grab = NULL;
|
||||
ClientPtr client;
|
||||
WindowPtr win;
|
||||
|
||||
if (!gi->has_listener || gi->listener.type == GESTURE_LISTENER_NONGESTURE_GRAB) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!RetrieveGestureDeliveryData(dev, ev, &gi->listener, &client, &win, &grab))
|
||||
return 0;
|
||||
|
||||
ev->gesture_event.deviceid = dev->id;
|
||||
|
||||
return DeliverOneGestureEvent(client, dev, gi, grab, win, ev);
|
||||
}
|
||||
|
||||
int
|
||||
InitProximityClassDeviceStruct(DeviceIntPtr dev)
|
||||
{
|
||||
|
@ -2379,8 +2625,8 @@ GrabWindow(ClientPtr client, DeviceIntPtr dev, int type,
|
|||
|
||||
/* Touch grab */
|
||||
int
|
||||
GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
|
||||
GrabParameters *param, GrabMask *mask)
|
||||
GrabTouchOrGesture(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
|
||||
int type, GrabParameters *param, GrabMask *mask)
|
||||
{
|
||||
WindowPtr pWin;
|
||||
GrabPtr grab;
|
||||
|
@ -2398,7 +2644,7 @@ GrabTouch(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr mod_dev,
|
|||
return rc;
|
||||
|
||||
grab = CreateGrab(client->index, dev, mod_dev, pWin, XI2,
|
||||
mask, param, XI_TouchBegin, 0, NullWindow, NullCursor);
|
||||
mask, param, type, 0, NullWindow, NullCursor);
|
||||
if (!grab)
|
||||
return BadAlloc;
|
||||
|
||||
|
|
80
Xi/extinit.c
80
Xi/extinit.c
|
@ -850,6 +850,74 @@ SBarrierEvent(xXIBarrierEvent * from,
|
|||
swapl(&to->eventid);
|
||||
}
|
||||
|
||||
static void
|
||||
SGesturePinchEvent(xXIGesturePinchEvent* from,
|
||||
xXIGesturePinchEvent* to)
|
||||
{
|
||||
*to = *from;
|
||||
|
||||
swaps(&to->sequenceNumber);
|
||||
swapl(&to->length);
|
||||
swaps(&to->evtype);
|
||||
swaps(&to->deviceid);
|
||||
swapl(&to->time);
|
||||
swapl(&to->detail);
|
||||
swapl(&to->root);
|
||||
swapl(&to->event);
|
||||
swapl(&to->child);
|
||||
swapl(&to->root_x);
|
||||
swapl(&to->root_y);
|
||||
swapl(&to->event_x);
|
||||
swapl(&to->event_y);
|
||||
|
||||
swapl(&to->delta_x);
|
||||
swapl(&to->delta_y);
|
||||
swapl(&to->delta_unaccel_x);
|
||||
swapl(&to->delta_unaccel_y);
|
||||
swapl(&to->scale);
|
||||
swapl(&to->delta_angle);
|
||||
swaps(&to->sourceid);
|
||||
|
||||
swapl(&to->mods.base_mods);
|
||||
swapl(&to->mods.latched_mods);
|
||||
swapl(&to->mods.locked_mods);
|
||||
swapl(&to->mods.effective_mods);
|
||||
swapl(&to->flags);
|
||||
}
|
||||
|
||||
static void
|
||||
SGestureSwipeEvent(xXIGestureSwipeEvent* from,
|
||||
xXIGestureSwipeEvent* to)
|
||||
{
|
||||
*to = *from;
|
||||
|
||||
swaps(&to->sequenceNumber);
|
||||
swapl(&to->length);
|
||||
swaps(&to->evtype);
|
||||
swaps(&to->deviceid);
|
||||
swapl(&to->time);
|
||||
swapl(&to->detail);
|
||||
swapl(&to->root);
|
||||
swapl(&to->event);
|
||||
swapl(&to->child);
|
||||
swapl(&to->root_x);
|
||||
swapl(&to->root_y);
|
||||
swapl(&to->event_x);
|
||||
swapl(&to->event_y);
|
||||
|
||||
swapl(&to->delta_x);
|
||||
swapl(&to->delta_y);
|
||||
swapl(&to->delta_unaccel_x);
|
||||
swapl(&to->delta_unaccel_y);
|
||||
swaps(&to->sourceid);
|
||||
|
||||
swapl(&to->mods.base_mods);
|
||||
swapl(&to->mods.latched_mods);
|
||||
swapl(&to->mods.locked_mods);
|
||||
swapl(&to->mods.effective_mods);
|
||||
swapl(&to->flags);
|
||||
}
|
||||
|
||||
/** Event swapping function for XI2 events. */
|
||||
void _X_COLD
|
||||
XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
|
||||
|
@ -901,6 +969,18 @@ XI2EventSwap(xGenericEvent *from, xGenericEvent *to)
|
|||
SBarrierEvent((xXIBarrierEvent *) from,
|
||||
(xXIBarrierEvent *) to);
|
||||
break;
|
||||
case XI_GesturePinchBegin:
|
||||
case XI_GesturePinchUpdate:
|
||||
case XI_GesturePinchEnd:
|
||||
SGesturePinchEvent((xXIGesturePinchEvent*) from,
|
||||
(xXIGesturePinchEvent*) to);
|
||||
break;
|
||||
case XI_GestureSwipeBegin:
|
||||
case XI_GestureSwipeUpdate:
|
||||
case XI_GestureSwipeEnd:
|
||||
SGestureSwipeEvent((xXIGestureSwipeEvent*) from,
|
||||
(xXIGestureSwipeEvent*) to);
|
||||
break;
|
||||
default:
|
||||
ErrorF("[Xi] Unknown event type to swap. This is a bug.\n");
|
||||
break;
|
||||
|
|
|
@ -39,6 +39,6 @@
|
|||
int SProcXIChangeHierarchy(ClientPtr /* client */ );
|
||||
int ProcXIChangeHierarchy(ClientPtr /* client */ );
|
||||
|
||||
void XISendDeviceHierarchyEvent(int flags[]);
|
||||
void XISendDeviceHierarchyEvent(int flags[MAXDEVICES]);
|
||||
|
||||
#endif /* CHDEVHIER_H */
|
||||
|
|
|
@ -114,14 +114,18 @@ ProcXIPassiveGrabDevice(ClientPtr client)
|
|||
stuff->grab_type != XIGrabtypeKeycode &&
|
||||
stuff->grab_type != XIGrabtypeEnter &&
|
||||
stuff->grab_type != XIGrabtypeFocusIn &&
|
||||
stuff->grab_type != XIGrabtypeTouchBegin) {
|
||||
stuff->grab_type != XIGrabtypeTouchBegin &&
|
||||
stuff->grab_type != XIGrabtypeGesturePinchBegin &&
|
||||
stuff->grab_type != XIGrabtypeGestureSwipeBegin) {
|
||||
client->errorValue = stuff->grab_type;
|
||||
return BadValue;
|
||||
}
|
||||
|
||||
if ((stuff->grab_type == XIGrabtypeEnter ||
|
||||
stuff->grab_type == XIGrabtypeFocusIn ||
|
||||
stuff->grab_type == XIGrabtypeTouchBegin) && stuff->detail != 0) {
|
||||
stuff->grab_type == XIGrabtypeTouchBegin ||
|
||||
stuff->grab_type == XIGrabtypeGesturePinchBegin ||
|
||||
stuff->grab_type == XIGrabtypeGestureSwipeBegin) && stuff->detail != 0) {
|
||||
client->errorValue = stuff->detail;
|
||||
return BadValue;
|
||||
}
|
||||
|
@ -217,7 +221,16 @@ ProcXIPassiveGrabDevice(ClientPtr client)
|
|||
status = GrabWindow(client, dev, stuff->grab_type, ¶m, &mask);
|
||||
break;
|
||||
case XIGrabtypeTouchBegin:
|
||||
status = GrabTouch(client, dev, mod_dev, ¶m, &mask);
|
||||
status = GrabTouchOrGesture(client, dev, mod_dev, XI_TouchBegin,
|
||||
¶m, &mask);
|
||||
break;
|
||||
case XIGrabtypeGesturePinchBegin:
|
||||
status = GrabTouchOrGesture(client, dev, mod_dev,
|
||||
XI_GesturePinchBegin, ¶m, &mask);
|
||||
break;
|
||||
case XIGrabtypeGestureSwipeBegin:
|
||||
status = GrabTouchOrGesture(client, dev, mod_dev,
|
||||
XI_GestureSwipeBegin, ¶m, &mask);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -307,7 +320,9 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
|
|||
stuff->grab_type != XIGrabtypeKeycode &&
|
||||
stuff->grab_type != XIGrabtypeEnter &&
|
||||
stuff->grab_type != XIGrabtypeFocusIn &&
|
||||
stuff->grab_type != XIGrabtypeTouchBegin) {
|
||||
stuff->grab_type != XIGrabtypeTouchBegin &&
|
||||
stuff->grab_type != XIGrabtypeGesturePinchBegin &&
|
||||
stuff->grab_type != XIGrabtypeGestureSwipeBegin) {
|
||||
client->errorValue = stuff->grab_type;
|
||||
return BadValue;
|
||||
}
|
||||
|
@ -348,6 +363,12 @@ ProcXIPassiveUngrabDevice(ClientPtr client)
|
|||
case XIGrabtypeTouchBegin:
|
||||
tempGrab->type = XI_TouchBegin;
|
||||
break;
|
||||
case XIGrabtypeGesturePinchBegin:
|
||||
tempGrab->type = XI_GesturePinchBegin;
|
||||
break;
|
||||
case XIGrabtypeGestureSwipeBegin:
|
||||
tempGrab->type = XI_GestureSwipeBegin;
|
||||
break;
|
||||
}
|
||||
tempGrab->grabtype = XI2;
|
||||
tempGrab->modifierDevice = mod_dev;
|
||||
|
|
|
@ -43,6 +43,9 @@
|
|||
#include "xace.h"
|
||||
#include "inpututils.h"
|
||||
|
||||
#include "exglobals.h"
|
||||
#include "privates.h"
|
||||
|
||||
#include "xiquerydevice.h"
|
||||
|
||||
static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d);
|
||||
|
@ -234,6 +237,9 @@ SizeDeviceClasses(DeviceIntPtr dev)
|
|||
if (dev->touch)
|
||||
len += sizeof(xXITouchInfo);
|
||||
|
||||
if (dev->gesture)
|
||||
len += sizeof(xXIGestureInfo);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -464,6 +470,46 @@ SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch)
|
|||
swaps(&touch->sourceid);
|
||||
}
|
||||
|
||||
static Bool ShouldListGestureInfo(ClientPtr client)
|
||||
{
|
||||
/* libxcb 14.1 and older are not forwards-compatible with new device classes as it does not
|
||||
* properly ignore unknown device classes. Since breaking libxcb would break quite a lot of
|
||||
* applications, we instead report Gesture device class only if the client advertised support
|
||||
* for XI 2.4. Clients may still not work in cases when a client advertises XI 2.4 support
|
||||
* and then a completely separate module within the client uses broken libxcb to call
|
||||
* XIQueryDevice.
|
||||
*/
|
||||
XIClientPtr pXIClient = dixLookupPrivate(&client->devPrivates, XIClientPrivateKey);
|
||||
if (pXIClient->major_version) {
|
||||
return version_compare(pXIClient->major_version, pXIClient->minor_version, 2, 4) >= 0;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* List gesture information
|
||||
*
|
||||
* @return The number of bytes written into info.
|
||||
*/
|
||||
static int
|
||||
ListGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture)
|
||||
{
|
||||
gesture->type = XIGestureClass;
|
||||
gesture->length = sizeof(xXIGestureInfo) >> 2;
|
||||
gesture->sourceid = dev->gesture->sourceid;
|
||||
gesture->num_touches = dev->gesture->max_touches;
|
||||
|
||||
return gesture->length << 2;
|
||||
}
|
||||
|
||||
static void
|
||||
SwapGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture)
|
||||
{
|
||||
swaps(&gesture->type);
|
||||
swaps(&gesture->length);
|
||||
swaps(&gesture->sourceid);
|
||||
}
|
||||
|
||||
int
|
||||
GetDeviceUse(DeviceIntPtr dev, uint16_t * attachment)
|
||||
{
|
||||
|
@ -567,6 +613,13 @@ ListDeviceClasses(ClientPtr client, DeviceIntPtr dev,
|
|||
total_len += len;
|
||||
}
|
||||
|
||||
if (dev->gesture && ShouldListGestureInfo(client)) {
|
||||
(*nclasses)++;
|
||||
len = ListGestureInfo(dev, (xXIGestureInfo *) any);
|
||||
any += len;
|
||||
total_len += len;
|
||||
}
|
||||
|
||||
return total_len;
|
||||
}
|
||||
|
||||
|
@ -598,7 +651,9 @@ SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info)
|
|||
case XITouchClass:
|
||||
SwapTouchInfo(dev, (xXITouchInfo *) any);
|
||||
break;
|
||||
|
||||
case XIGestureClass:
|
||||
SwapGestureInfo(dev, (xXIGestureInfo *) any);
|
||||
break;
|
||||
}
|
||||
|
||||
any += len * 4;
|
||||
|
|
|
@ -226,8 +226,41 @@ ProcXISelectEvents(ClientPtr client)
|
|||
return BadValue;
|
||||
}
|
||||
|
||||
/* Only one client per window may select for touch events on the
|
||||
* same devices, including master devices.
|
||||
/* All three pinch gesture events must be selected at once */
|
||||
if ((BitIsOn(bits, XI_GesturePinchBegin) ||
|
||||
BitIsOn(bits, XI_GesturePinchUpdate) ||
|
||||
BitIsOn(bits, XI_GesturePinchEnd)) &&
|
||||
(!BitIsOn(bits, XI_GesturePinchBegin) ||
|
||||
!BitIsOn(bits, XI_GesturePinchUpdate) ||
|
||||
!BitIsOn(bits, XI_GesturePinchEnd))) {
|
||||
client->errorValue = XI_GesturePinchBegin;
|
||||
return BadValue;
|
||||
}
|
||||
|
||||
/* All three swipe gesture events must be selected at once. Note
|
||||
that the XI_GestureSwipeEnd is at index 32 which is on the next
|
||||
4-byte mask element */
|
||||
if (evmask->mask_len == 1 &&
|
||||
(BitIsOn(bits, XI_GestureSwipeBegin) ||
|
||||
BitIsOn(bits, XI_GestureSwipeUpdate)))
|
||||
{
|
||||
client->errorValue = XI_GestureSwipeBegin;
|
||||
return BadValue;
|
||||
}
|
||||
|
||||
if (evmask->mask_len >= 2 &&
|
||||
(BitIsOn(bits, XI_GestureSwipeBegin) ||
|
||||
BitIsOn(bits, XI_GestureSwipeUpdate) ||
|
||||
BitIsOn(bits, XI_GestureSwipeEnd)) &&
|
||||
(!BitIsOn(bits, XI_GestureSwipeBegin) ||
|
||||
!BitIsOn(bits, XI_GestureSwipeUpdate) ||
|
||||
!BitIsOn(bits, XI_GestureSwipeEnd))) {
|
||||
client->errorValue = XI_GestureSwipeBegin;
|
||||
return BadValue;
|
||||
}
|
||||
|
||||
/* Only one client per window may select for touch or gesture events
|
||||
* on the same devices, including master devices.
|
||||
* XXX: This breaks if a device goes from floating to attached. */
|
||||
if (BitIsOn(bits, XI_TouchBegin)) {
|
||||
rc = check_for_touch_selection_conflicts(client,
|
||||
|
@ -237,6 +270,22 @@ ProcXISelectEvents(ClientPtr client)
|
|||
if (rc != Success)
|
||||
return rc;
|
||||
}
|
||||
if (BitIsOn(bits, XI_GesturePinchBegin)) {
|
||||
rc = check_for_touch_selection_conflicts(client,
|
||||
win,
|
||||
evmask->deviceid,
|
||||
XI_GesturePinchBegin);
|
||||
if (rc != Success)
|
||||
return rc;
|
||||
}
|
||||
if (BitIsOn(bits, XI_GestureSwipeBegin)) {
|
||||
rc = check_for_touch_selection_conflicts(client,
|
||||
win,
|
||||
evmask->deviceid,
|
||||
XI_GestureSwipeBegin);
|
||||
if (rc != Success)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (XICheckInvalidMaskBits(client, (unsigned char *) &evmask[1],
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#! /bin/sh
|
||||
|
||||
srcdir=`dirname "$0"`
|
||||
test -z "$srcdir" && srcdir=.
|
||||
|
||||
ORIGDIR=`pwd`
|
||||
cd "$srcdir"
|
||||
|
||||
autoreconf --force -v --install || exit 1
|
||||
cd "$ORIGDIR" || exit $?
|
||||
|
||||
git config --local --get format.subjectPrefix ||
|
||||
git config --local format.subjectPrefix "PATCH xserver"
|
||||
|
||||
if test -z "$NOCONFIGURE"; then
|
||||
exec "$srcdir"/configure "$@"
|
||||
fi
|
|
@ -0,0 +1,15 @@
|
|||
noinst_LTLIBRARIES = libcomposite.la
|
||||
|
||||
AM_CFLAGS = $(DIX_CFLAGS)
|
||||
|
||||
if XORG
|
||||
sdk_HEADERS = compositeext.h
|
||||
endif
|
||||
|
||||
libcomposite_la_SOURCES = \
|
||||
compalloc.c \
|
||||
compext.c \
|
||||
compint.h \
|
||||
compinit.c \
|
||||
compoverlay.c \
|
||||
compwindow.c
|
|
@ -15,3 +15,7 @@ libxserver_composite = static_library('libxserver_composite',
|
|||
include_directories: inc,
|
||||
dependencies: common_dep,
|
||||
)
|
||||
|
||||
if build_xorg
|
||||
install_data(hdrs_composite, install_dir: xorgsdkdir)
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# Collection of quirks and blacklist/whitelists for specific devices.
|
||||
|
||||
|
||||
# Accelerometer device, posts data through ABS_X/ABS_Y, making X unusable
|
||||
# http://bugs.freedesktop.org/show_bug.cgi?id=22442
|
||||
Section "InputClass"
|
||||
Identifier "ThinkPad HDAPS accelerometer blacklist"
|
||||
MatchProduct "ThinkPad HDAPS accelerometer data"
|
||||
Option "Ignore" "on"
|
||||
EndSection
|
||||
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=523914
|
||||
# Mouse does not move in PV Xen guest
|
||||
# Explicitly tell evdev to not ignore the absolute axes.
|
||||
Section "InputClass"
|
||||
Identifier "Xen Virtual Pointer axis blacklist"
|
||||
MatchProduct "Xen Virtual Pointer"
|
||||
Option "IgnoreAbsoluteAxes" "off"
|
||||
Option "IgnoreRelativeAxes" "off"
|
||||
EndSection
|
||||
|
||||
# https://bugs.freedesktop.org/show_bug.cgi?id=55867
|
||||
# Bug 55867 - Doesn't know how to tag XI_TRACKBALL
|
||||
Section "InputClass"
|
||||
Identifier "Tag trackballs as XI_TRACKBALL"
|
||||
MatchProduct "trackball"
|
||||
MatchDriver "evdev"
|
||||
Option "TypeName" "TRACKBALL"
|
||||
EndSection
|
||||
|
||||
# https://bugs.freedesktop.org/show_bug.cgi?id=62831
|
||||
# Bug 62831 - Mionix Naos 5000 mouse detected incorrectly
|
||||
Section "InputClass"
|
||||
Identifier "Tag Mionix Naos 5000 mouse XI_MOUSE"
|
||||
MatchProduct "La-VIEW Technology Naos 5000 Mouse"
|
||||
MatchDriver "evdev"
|
||||
Option "TypeName" "MOUSE"
|
||||
EndSection
|
|
@ -0,0 +1,41 @@
|
|||
AM_CFLAGS = $(DIX_CFLAGS)
|
||||
|
||||
noinst_LTLIBRARIES = libconfig.la
|
||||
libconfig_la_SOURCES = config.c config-backends.h
|
||||
libconfig_la_LIBADD =
|
||||
|
||||
if NEED_DBUS
|
||||
AM_CFLAGS += $(DBUS_CFLAGS)
|
||||
libconfig_la_SOURCES += dbus-core.c
|
||||
libconfig_la_LIBADD += $(DBUS_LIBS)
|
||||
endif
|
||||
|
||||
if CONFIG_UDEV
|
||||
|
||||
AM_CFLAGS += $(UDEV_CFLAGS)
|
||||
libconfig_la_SOURCES += udev.c
|
||||
libconfig_la_LIBADD += $(UDEV_LIBS)
|
||||
|
||||
if XORG
|
||||
xorgconfddir = $(datadir)/X11/$(XF86CONFIGDIR)
|
||||
xorgconfd_DATA = 10-quirks.conf
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
if CONFIG_HAL
|
||||
AM_CFLAGS += $(HAL_CFLAGS)
|
||||
libconfig_la_SOURCES += hal.c
|
||||
libconfig_la_LIBADD += $(HAL_LIBS)
|
||||
|
||||
else
|
||||
|
||||
if CONFIG_WSCONS
|
||||
libconfig_la_SOURCES += wscons.c
|
||||
endif # CONFIG_WSCONS
|
||||
|
||||
endif # !CONFIG_HAL
|
||||
|
||||
endif # !CONFIG_UDEV
|
||||
|
||||
EXTRA_DIST = x11-input.fdi fdi2iclass.py 10-quirks.conf
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright © 2006-2007 Daniel Stone
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
#include "input.h"
|
||||
#include "list.h"
|
||||
|
||||
void remove_devices(const char *backend, const char *config_info);
|
||||
BOOL device_is_duplicate(const char *config_info);
|
||||
|
||||
#ifdef CONFIG_UDEV
|
||||
int config_udev_pre_init(void);
|
||||
int config_udev_init(void);
|
||||
void config_udev_fini(void);
|
||||
void config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback);
|
||||
#elif defined(CONFIG_HAL)
|
||||
int config_hal_init(void);
|
||||
void config_hal_fini(void);
|
||||
#elif defined(CONFIG_WSCONS)
|
||||
int config_wscons_init(void);
|
||||
void config_wscons_fini(void);
|
||||
#endif
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright © 2006-2007 Daniel Stone
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include "os.h"
|
||||
#include "inputstr.h"
|
||||
#include "hotplug.h"
|
||||
#include "config-backends.h"
|
||||
#include "systemd-logind.h"
|
||||
|
||||
void
|
||||
config_pre_init(void)
|
||||
{
|
||||
#ifdef CONFIG_UDEV
|
||||
if (!config_udev_pre_init())
|
||||
ErrorF("[config] failed to pre-init udev\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
config_init(void)
|
||||
{
|
||||
#ifdef CONFIG_UDEV
|
||||
if (!config_udev_init())
|
||||
ErrorF("[config] failed to initialise udev\n");
|
||||
#elif defined(CONFIG_HAL)
|
||||
if (!config_hal_init())
|
||||
ErrorF("[config] failed to initialise HAL\n");
|
||||
#elif defined(CONFIG_WSCONS)
|
||||
if (!config_wscons_init())
|
||||
ErrorF("[config] failed to initialise wscons\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
config_fini(void)
|
||||
{
|
||||
#if defined(CONFIG_UDEV)
|
||||
config_udev_fini();
|
||||
#elif defined(CONFIG_HAL)
|
||||
config_hal_fini();
|
||||
#elif defined(CONFIG_WSCONS)
|
||||
config_wscons_fini();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
config_odev_probe(config_odev_probe_proc_ptr probe_callback)
|
||||
{
|
||||
#if defined(CONFIG_UDEV_KMS)
|
||||
config_udev_odev_probe(probe_callback);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
remove_device(const char *backend, DeviceIntPtr dev)
|
||||
{
|
||||
/* this only gets called for devices that have already been added */
|
||||
LogMessage(X_INFO, "config/%s: removing device %s\n", backend, dev->name);
|
||||
|
||||
/* Call PIE here so we don't try to dereference a device that's
|
||||
* already been removed. */
|
||||
input_lock();
|
||||
ProcessInputEvents();
|
||||
DeleteInputDeviceRequest(dev);
|
||||
input_unlock();
|
||||
}
|
||||
|
||||
void
|
||||
remove_devices(const char *backend, const char *config_info)
|
||||
{
|
||||
DeviceIntPtr dev, next;
|
||||
|
||||
for (dev = inputInfo.devices; dev; dev = next) {
|
||||
next = dev->next;
|
||||
if (dev->config_info && strcmp(dev->config_info, config_info) == 0)
|
||||
remove_device(backend, dev);
|
||||
}
|
||||
for (dev = inputInfo.off_devices; dev; dev = next) {
|
||||
next = dev->next;
|
||||
if (dev->config_info && strcmp(dev->config_info, config_info) == 0)
|
||||
remove_device(backend, dev);
|
||||
}
|
||||
|
||||
RemoveInputDeviceTraces(config_info);
|
||||
}
|
||||
|
||||
BOOL
|
||||
device_is_duplicate(const char *config_info)
|
||||
{
|
||||
DeviceIntPtr dev;
|
||||
|
||||
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||||
if (dev->config_info && (strcmp(dev->config_info, config_info) == 0))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (dev = inputInfo.off_devices; dev; dev = dev->next) {
|
||||
if (dev->config_info && (strcmp(dev->config_info, config_info) == 0))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct OdevAttributes *
|
||||
config_odev_allocate_attributes(void)
|
||||
{
|
||||
struct OdevAttributes *attribs =
|
||||
xnfcalloc(1, sizeof (struct OdevAttributes));
|
||||
attribs->fd = -1;
|
||||
return attribs;
|
||||
}
|
||||
|
||||
void
|
||||
config_odev_free_attributes(struct OdevAttributes *attribs)
|
||||
{
|
||||
if (attribs->fd != -1)
|
||||
systemd_logind_release_fd(attribs->major, attribs->minor, attribs->fd);
|
||||
free(attribs->path);
|
||||
free(attribs->syspath);
|
||||
free(attribs->busid);
|
||||
free(attribs->driver);
|
||||
free(attribs);
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
D-BUS Configuration API v2
|
||||
----------------------------
|
||||
|
||||
The X server will register the bus name org.x.config.displayN, and the
|
||||
object /org/x/config/N, where N is the display number.
|
||||
|
||||
Currently only hotplugging of input devices is supported.
|
||||
|
||||
org.x.config.input:
|
||||
org.x.config.input.version:
|
||||
Returns one unsigned int32, which is the API version.
|
||||
|
||||
org.x.config.input.add:
|
||||
Takes an argument of key/value option pairs in arrays, e.g.:
|
||||
[ss][ss][ss][ss]
|
||||
is the signature for four options. These options will be passed
|
||||
to the input driver as with any others.
|
||||
Option names beginning with _ are not allowed; they are reserved
|
||||
for internal use.
|
||||
|
||||
Returns a number of signed int32s. Positive integers are the
|
||||
device IDs of new devices; negative numbers are X error codes,
|
||||
as defined in X.h. BadMatch will be returned if the options
|
||||
given do not match any device. BadValue is returned for a malformed
|
||||
message. (Example: 8 is new device ID 8; -8 is BadMatch.)
|
||||
|
||||
Notably, BadAlloc is never returned: the server internally signals
|
||||
to D-BUS that the attempt failed for lack of memory.
|
||||
|
||||
org.x.config.input.remove:
|
||||
Takes one uint32 argument, which is the device ID to remove, i.e.:
|
||||
u
|
||||
is the signature.
|
||||
|
||||
Returns one signed int32 which represents an X status as defined in
|
||||
X.h. See org.x.config.input.add. Error codes are negative numbers.
|
||||
|
||||
org.x.config.input.listDevices:
|
||||
Lists the currently active devices. No argument.
|
||||
Return value is sequence of [<id> <name>] [<id> <name>] ..., i.e. [us].
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* Copyright © 2006-2007 Daniel Stone
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "dix.h"
|
||||
#include "os.h"
|
||||
#include "dbus-core.h"
|
||||
|
||||
/* How often to attempt reconnecting when we get booted off the bus. */
|
||||
#define RECONNECT_DELAY (10 * 1000) /* in ms */
|
||||
|
||||
struct dbus_core_info {
|
||||
int fd;
|
||||
DBusConnection *connection;
|
||||
OsTimerPtr timer;
|
||||
struct dbus_core_hook *hooks;
|
||||
};
|
||||
static struct dbus_core_info bus_info = { .fd = -1 };
|
||||
|
||||
static CARD32 reconnect_timer(OsTimerPtr timer, CARD32 time, void *arg);
|
||||
|
||||
static void
|
||||
socket_handler(int fd, int ready, void *data)
|
||||
{
|
||||
struct dbus_core_info *info = data;
|
||||
|
||||
if (info->connection) {
|
||||
do {
|
||||
dbus_connection_read_write_dispatch(info->connection, 0);
|
||||
} while (info->connection &&
|
||||
dbus_connection_get_is_connected(info->connection) &&
|
||||
dbus_connection_get_dispatch_status(info->connection) ==
|
||||
DBUS_DISPATCH_DATA_REMAINS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect (if we haven't already been forcefully disconnected), clean up
|
||||
* after ourselves, and call all registered disconnect hooks.
|
||||
*/
|
||||
static void
|
||||
teardown(void)
|
||||
{
|
||||
struct dbus_core_hook *hook;
|
||||
|
||||
if (bus_info.timer) {
|
||||
TimerFree(bus_info.timer);
|
||||
bus_info.timer = NULL;
|
||||
}
|
||||
|
||||
/* We should really have pre-disconnect hooks and run them here, for
|
||||
* completeness. But then it gets awkward, given that you can't
|
||||
* guarantee that they'll be called ... */
|
||||
if (bus_info.connection)
|
||||
dbus_connection_unref(bus_info.connection);
|
||||
|
||||
if (bus_info.fd != -1)
|
||||
RemoveNotifyFd(bus_info.fd);
|
||||
bus_info.fd = -1;
|
||||
bus_info.connection = NULL;
|
||||
|
||||
for (hook = bus_info.hooks; hook; hook = hook->next) {
|
||||
if (hook->disconnect)
|
||||
hook->disconnect(hook->data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a filter, which only handles the disconnected signal, which
|
||||
* doesn't go to the normal message handling function. This takes
|
||||
* precedence over the message handling function, so have have to be
|
||||
* careful to ignore anything we don't want to deal with here.
|
||||
*/
|
||||
static DBusHandlerResult
|
||||
message_filter(DBusConnection * connection, DBusMessage * message, void *data)
|
||||
{
|
||||
/* If we get disconnected, then take everything down, and attempt to
|
||||
* reconnect immediately (assuming it's just a restart). The
|
||||
* connection isn't valid at this point, so throw it out immediately. */
|
||||
if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
|
||||
DebugF("[dbus-core] disconnected from bus\n");
|
||||
bus_info.connection = NULL;
|
||||
teardown();
|
||||
|
||||
if (bus_info.timer)
|
||||
TimerFree(bus_info.timer);
|
||||
bus_info.timer = TimerSet(NULL, 0, 1, reconnect_timer, NULL);
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to connect to the system bus, and set a filter to deal with
|
||||
* disconnection (see message_filter above).
|
||||
*
|
||||
* @return 1 on success, 0 on failure.
|
||||
*/
|
||||
static int
|
||||
connect_to_bus(void)
|
||||
{
|
||||
DBusError error;
|
||||
struct dbus_core_hook *hook;
|
||||
|
||||
dbus_error_init(&error);
|
||||
bus_info.connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
|
||||
if (!bus_info.connection || dbus_error_is_set(&error)) {
|
||||
LogMessage(X_ERROR, "dbus-core: error connecting to system bus: %s (%s)\n",
|
||||
error.name, error.message);
|
||||
goto err_begin;
|
||||
}
|
||||
|
||||
/* Thankyou. Really, thankyou. */
|
||||
dbus_connection_set_exit_on_disconnect(bus_info.connection, FALSE);
|
||||
|
||||
if (!dbus_connection_get_unix_fd(bus_info.connection, &bus_info.fd)) {
|
||||
ErrorF("[dbus-core] couldn't get fd for system bus\n");
|
||||
goto err_unref;
|
||||
}
|
||||
|
||||
if (!dbus_connection_add_filter(bus_info.connection, message_filter,
|
||||
&bus_info, NULL)) {
|
||||
ErrorF("[dbus-core] couldn't add filter: %s (%s)\n", error.name,
|
||||
error.message);
|
||||
goto err_fd;
|
||||
}
|
||||
|
||||
dbus_error_free(&error);
|
||||
SetNotifyFd(bus_info.fd, socket_handler, X_NOTIFY_READ, &bus_info);
|
||||
|
||||
for (hook = bus_info.hooks; hook; hook = hook->next) {
|
||||
if (hook->connect)
|
||||
hook->connect(bus_info.connection, hook->data);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
err_fd:
|
||||
bus_info.fd = -1;
|
||||
err_unref:
|
||||
dbus_connection_unref(bus_info.connection);
|
||||
bus_info.connection = NULL;
|
||||
err_begin:
|
||||
dbus_error_free(&error);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static CARD32
|
||||
reconnect_timer(OsTimerPtr timer, CARD32 time, void *arg)
|
||||
{
|
||||
if (connect_to_bus()) {
|
||||
TimerFree(bus_info.timer);
|
||||
bus_info.timer = NULL;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return RECONNECT_DELAY;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
dbus_core_add_hook(struct dbus_core_hook *hook)
|
||||
{
|
||||
struct dbus_core_hook **prev;
|
||||
|
||||
for (prev = &bus_info.hooks; *prev; prev = &(*prev)->next);
|
||||
|
||||
hook->next = NULL;
|
||||
*prev = hook;
|
||||
|
||||
/* If we're already connected, call the connect hook. */
|
||||
if (bus_info.connection)
|
||||
hook->connect(bus_info.connection, hook->data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
dbus_core_remove_hook(struct dbus_core_hook *hook)
|
||||
{
|
||||
struct dbus_core_hook **prev;
|
||||
|
||||
for (prev = &bus_info.hooks; *prev; prev = &(*prev)->next) {
|
||||
if (*prev == hook) {
|
||||
*prev = hook->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
dbus_core_init(void)
|
||||
{
|
||||
memset(&bus_info, 0, sizeof(bus_info));
|
||||
bus_info.fd = -1;
|
||||
bus_info.hooks = NULL;
|
||||
if (!connect_to_bus())
|
||||
bus_info.timer = TimerSet(NULL, 0, 1, reconnect_timer, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
dbus_core_fini(void)
|
||||
{
|
||||
teardown();
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Convert xorg keys from hal FDIs files to xorg.conf InputClass sections.
|
||||
# Modified from Martin Pitt's original fdi2mpi.py script:
|
||||
# http://cgit.freedesktop.org/media-player-info/tree/tools/fdi2mpi.py
|
||||
#
|
||||
# (C) 2010 Dan Nicholson
|
||||
# (C) 2009 Canonical Ltd.
|
||||
# Author: Dan Nicholson <dbn.lists@gmail.com>
|
||||
# Author: Martin Pitt <martin.pitt@ubuntu.com>
|
||||
#
|
||||
# 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
|
||||
# fur- nished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice 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,
|
||||
# FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
|
||||
# NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import sys, xml.dom.minidom
|
||||
|
||||
# dict converting <match> tags to Match* entries
|
||||
match_table = {
|
||||
'info.product': 'MatchProduct',
|
||||
'input.product': 'MatchProduct',
|
||||
'info.vendor': 'MatchVendor',
|
||||
'input.vendor': 'MatchVendor',
|
||||
'info.device': 'MatchDevicePath',
|
||||
'linux.device_file': 'MatchDevicePath',
|
||||
'/org/freedesktop/Hal/devices/computer:system.kernel.name': 'MatchOS',
|
||||
'@info.parent:pnp.id': 'MatchPnPID',
|
||||
}
|
||||
|
||||
# dict converting info.capabilities list to Match* entries
|
||||
cap_match_table = {
|
||||
'input.keys': 'MatchIsKeyboard',
|
||||
'input.keyboard': 'MatchIsKeyboard',
|
||||
'input.keypad': 'MatchIsKeyboard',
|
||||
'input.mouse': 'MatchIsPointer',
|
||||
'input.joystick': 'MatchIsJoystick',
|
||||
'input.tablet': 'MatchIsTablet',
|
||||
'input.touchpad': 'MatchIsTouchpad',
|
||||
'input.touchscreen': 'MatchIsTouchscreen',
|
||||
}
|
||||
|
||||
def device_glob(path):
|
||||
'''Convert a contains device path to a glob entry'''
|
||||
if path[0] != '/':
|
||||
path = '*' + path
|
||||
return path + '*'
|
||||
|
||||
def parse_match(node):
|
||||
'''Parse a <match> tag to a tuple with InputClass values'''
|
||||
match = None
|
||||
value = None
|
||||
booltype = False
|
||||
|
||||
# see what type of key we have
|
||||
if node.attributes.has_key('key'):
|
||||
key = node.attributes['key'].nodeValue
|
||||
if key in match_table:
|
||||
match = match_table[key]
|
||||
elif key == 'info.capabilities':
|
||||
booltype = True
|
||||
|
||||
# bail out now if it's unrecognized
|
||||
if not match and not booltype:
|
||||
return (match, value)
|
||||
|
||||
if node.attributes.has_key('string'):
|
||||
value = node.attributes['string'].nodeValue
|
||||
elif node.attributes.has_key('contains'):
|
||||
value = node.attributes['contains'].nodeValue
|
||||
if match == 'MatchDevicePath':
|
||||
value = device_glob(value)
|
||||
elif booltype and value in cap_match_table:
|
||||
match = cap_match_table[value]
|
||||
value = 'yes'
|
||||
elif node.attributes.has_key('string_outof'):
|
||||
value = node.attributes['string_outof'].nodeValue.replace(';','|')
|
||||
elif node.attributes.has_key('contains_outof'):
|
||||
all_values = node.attributes['contains_outof'].nodeValue.split(';')
|
||||
for v in all_values:
|
||||
if match == 'MatchDevicePath':
|
||||
v = device_glob(v)
|
||||
elif match == 'MatchPnPID' and len(v) < 7:
|
||||
v += '*'
|
||||
if value:
|
||||
value += '|' + v
|
||||
else:
|
||||
value = v
|
||||
|
||||
return (match, value)
|
||||
|
||||
def parse_options(node):
|
||||
'''Parse the x11_* options and return InputClass entries'''
|
||||
driver = ''
|
||||
ignore = False
|
||||
options = []
|
||||
for n in node.childNodes:
|
||||
if n.nodeType != xml.dom.minidom.Node.ELEMENT_NODE:
|
||||
continue
|
||||
|
||||
tag = n.tagName
|
||||
key = n.attributes['key'].nodeValue
|
||||
value = ''
|
||||
|
||||
if n.hasChildNodes():
|
||||
content_node = n.childNodes[0]
|
||||
assert content_node.nodeType == xml.dom.Node.TEXT_NODE
|
||||
value = content_node.nodeValue
|
||||
|
||||
if tag == 'match':
|
||||
continue
|
||||
assert tag in ('addset', 'merge', 'append', 'remove')
|
||||
|
||||
if tag == 'remove' and key == 'input.x11_driver':
|
||||
ignore = True
|
||||
elif key == 'input.x11_driver':
|
||||
driver = value
|
||||
elif key.startswith('input.x11_options.'):
|
||||
option = key.split('.', 2)[2]
|
||||
options.append((option, value))
|
||||
|
||||
return (driver, ignore, options)
|
||||
|
||||
def is_match_node(node):
|
||||
'''Check if a node is a <match> element'''
|
||||
return node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE and \
|
||||
node.tagName == 'match'
|
||||
|
||||
def parse_all_matches(node):
|
||||
'''Parse a x11 match tag and any parents that don't supply their
|
||||
own options'''
|
||||
matches = []
|
||||
|
||||
while True:
|
||||
(key, value) = parse_match(node)
|
||||
if key and value:
|
||||
matches.append((key, value))
|
||||
|
||||
# walk up to a parent match node
|
||||
node = node.parentNode
|
||||
if node == None or not is_match_node(node):
|
||||
break
|
||||
|
||||
# leave if there other options at this level
|
||||
children = set([n.tagName for n in node.childNodes
|
||||
if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
|
||||
if children & set(['addset', 'merge', 'append']):
|
||||
break
|
||||
|
||||
return matches
|
||||
|
||||
# stupid counter to give "unique" rule names
|
||||
num_sections = 1
|
||||
def print_section(matches, driver, ignore, options):
|
||||
'''Print a valid InputClass section to stdout'''
|
||||
global num_sections
|
||||
print 'Section "InputClass"'
|
||||
print '\tIdentifier "Converted Class %d"' % num_sections
|
||||
num_sections += 1
|
||||
for m, v in matches:
|
||||
print '\t%s "%s"' % (m, v)
|
||||
if driver:
|
||||
print '\tDriver "%s"' % driver
|
||||
if ignore:
|
||||
print '\tOption "Ignore" "yes"'
|
||||
for o, v in options:
|
||||
print '\tOption "%s" "%s"' % (o, v)
|
||||
print 'EndSection'
|
||||
|
||||
def parse_fdi(fdi):
|
||||
'''Parse x11 matches from fdi'''
|
||||
# find all <match> leaf nodes
|
||||
num = 0
|
||||
for match_node in fdi.getElementsByTagName('match'):
|
||||
children = set([n.tagName for n in match_node.childNodes
|
||||
if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
|
||||
|
||||
# see if there are any options at this level
|
||||
(driver, ignore, options) = parse_options(match_node)
|
||||
if not driver and not ignore and not options:
|
||||
continue
|
||||
|
||||
matches = parse_all_matches(match_node)
|
||||
if num > 0:
|
||||
print
|
||||
print_section(matches, driver, ignore, options)
|
||||
num += 1
|
||||
|
||||
for f in sys.argv[1:]:
|
||||
parse_fdi(xml.dom.minidom.parse(f))
|
|
@ -0,0 +1,675 @@
|
|||
/*
|
||||
* Copyright © 2007 Daniel Stone
|
||||
* Copyright © 2007 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.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <hal/libhal.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "dbus-core.h"
|
||||
#include "input.h"
|
||||
#include "inputstr.h"
|
||||
#include "hotplug.h"
|
||||
#include "config-backends.h"
|
||||
#include "os.h"
|
||||
|
||||
#define LIBHAL_PROP_KEY "input.x11_options."
|
||||
#define LIBHAL_XKB_PROP_KEY "input.xkb."
|
||||
|
||||
struct config_hal_info {
|
||||
DBusConnection *system_bus;
|
||||
LibHalContext *hal_ctx;
|
||||
};
|
||||
|
||||
/* Used for special handling of xkb options. */
|
||||
struct xkb_options {
|
||||
char *layout;
|
||||
char *model;
|
||||
char *rules;
|
||||
char *variant;
|
||||
char *options;
|
||||
};
|
||||
|
||||
static void
|
||||
device_removed(LibHalContext * ctx, const char *udi)
|
||||
{
|
||||
char *value;
|
||||
|
||||
if (asprintf(&value, "hal:%s", udi) == -1)
|
||||
return;
|
||||
|
||||
remove_devices("hal", value);
|
||||
|
||||
free(value);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_prop_string(LibHalContext * hal_ctx, const char *udi, const char *name)
|
||||
{
|
||||
char *prop, *ret;
|
||||
|
||||
prop = libhal_device_get_property_string(hal_ctx, udi, name, NULL);
|
||||
LogMessageVerb(X_INFO, 10, "config/hal: getting %s on %s returned %s\n",
|
||||
name, udi, prop ? prop : "(null)");
|
||||
if (prop) {
|
||||
ret = strdup(prop);
|
||||
libhal_free_string(prop);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_prop_string_array(LibHalContext * hal_ctx, const char *udi,
|
||||
const char *prop)
|
||||
{
|
||||
char **props, *ret, *str;
|
||||
int i, len = 0;
|
||||
|
||||
props = libhal_device_get_property_strlist(hal_ctx, udi, prop, NULL);
|
||||
if (props) {
|
||||
for (i = 0; props[i]; i++)
|
||||
len += strlen(props[i]);
|
||||
|
||||
ret = calloc(sizeof(char), len + i); /* i - 1 commas, 1 NULL */
|
||||
if (!ret) {
|
||||
libhal_free_string_array(props);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
str = ret;
|
||||
for (i = 0; props[i]; i++) {
|
||||
strcpy(str, props[i]);
|
||||
str += strlen(props[i]);
|
||||
*str++ = ',';
|
||||
}
|
||||
*(str - 1) = '\0';
|
||||
|
||||
libhal_free_string_array(props);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
device_added(LibHalContext * hal_ctx, const char *udi)
|
||||
{
|
||||
char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL;
|
||||
char *hal_tags, *parent;
|
||||
InputOption *input_options = NULL;
|
||||
InputAttributes attrs = { 0 };
|
||||
DeviceIntPtr dev = NULL;
|
||||
DBusError error;
|
||||
struct xkb_options xkb_opts = { 0 };
|
||||
int rc;
|
||||
|
||||
LibHalPropertySet *set = NULL;
|
||||
LibHalPropertySetIterator set_iter;
|
||||
char *psi_key = NULL, *tmp_val;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
driver = get_prop_string(hal_ctx, udi, "input.x11_driver");
|
||||
if (!driver) {
|
||||
/* verbose, don't tell the user unless they _want_ to see it */
|
||||
LogMessageVerb(X_INFO, 7,
|
||||
"config/hal: no driver specified for device %s\n", udi);
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
path = get_prop_string(hal_ctx, udi, "input.device");
|
||||
if (!path) {
|
||||
LogMessage(X_WARNING,
|
||||
"config/hal: no driver or path specified for %s\n", udi);
|
||||
goto unwind;
|
||||
}
|
||||
attrs.device = strdup(path);
|
||||
|
||||
name = get_prop_string(hal_ctx, udi, "info.product");
|
||||
if (!name)
|
||||
name = strdup("(unnamed)");
|
||||
else
|
||||
attrs.product = strdup(name);
|
||||
|
||||
attrs.vendor = get_prop_string(hal_ctx, udi, "info.vendor");
|
||||
hal_tags = get_prop_string(hal_ctx, udi, "input.tags");
|
||||
attrs.tags = xstrtokenize(hal_tags, ",");
|
||||
free(hal_tags);
|
||||
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.keys", NULL))
|
||||
attrs.flags |= ATTR_KEY | ATTR_KEYBOARD;
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.mouse", NULL))
|
||||
attrs.flags |= ATTR_POINTER;
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.joystick", NULL))
|
||||
attrs.flags |= ATTR_JOYSTICK;
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.tablet", NULL))
|
||||
attrs.flags |= ATTR_TABLET;
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.tablet_pad", NULL))
|
||||
attrs.flags |= ATTR_TABLET_PAD;
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.touchpad", NULL))
|
||||
attrs.flags |= ATTR_TOUCHPAD;
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.touchscreen", NULL))
|
||||
attrs.flags |= ATTR_TOUCHSCREEN;
|
||||
|
||||
parent = get_prop_string(hal_ctx, udi, "info.parent");
|
||||
if (parent) {
|
||||
int usb_vendor, usb_product;
|
||||
char *old_parent;
|
||||
|
||||
/* construct USB ID in lowercase - "0000:ffff" */
|
||||
usb_vendor = libhal_device_get_property_int(hal_ctx, parent,
|
||||
"usb.vendor_id", NULL);
|
||||
LogMessageVerb(X_INFO, 10,
|
||||
"config/hal: getting usb.vendor_id on %s "
|
||||
"returned %04x\n", parent, usb_vendor);
|
||||
usb_product = libhal_device_get_property_int(hal_ctx, parent,
|
||||
"usb.product_id", NULL);
|
||||
LogMessageVerb(X_INFO, 10,
|
||||
"config/hal: getting usb.product_id on %s "
|
||||
"returned %04x\n", parent, usb_product);
|
||||
if (usb_vendor && usb_product)
|
||||
if (asprintf(&attrs.usb_id, "%04x:%04x", usb_vendor, usb_product)
|
||||
== -1)
|
||||
attrs.usb_id = NULL;
|
||||
|
||||
attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id");
|
||||
old_parent = parent;
|
||||
|
||||
while (!attrs.pnp_id &&
|
||||
(parent = get_prop_string(hal_ctx, parent, "info.parent"))) {
|
||||
attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id");
|
||||
|
||||
free(old_parent);
|
||||
old_parent = parent;
|
||||
}
|
||||
|
||||
free(old_parent);
|
||||
}
|
||||
|
||||
input_options = input_option_new(NULL, "_source", "server/hal");
|
||||
if (!input_options) {
|
||||
LogMessage(X_ERROR,
|
||||
"config/hal: couldn't allocate first key/value pair\n");
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
/* most drivers use device.. not path. evdev uses both however, but the
|
||||
* path version isn't documented apparently. support both for now. */
|
||||
input_options = input_option_new(input_options, "path", path);
|
||||
input_options = input_option_new(input_options, "device", path);
|
||||
|
||||
input_options = input_option_new(input_options, "driver", driver);
|
||||
input_options = input_option_new(input_options, "name", name);
|
||||
|
||||
if (asprintf(&config_info, "hal:%s", udi) == -1) {
|
||||
config_info = NULL;
|
||||
LogMessage(X_ERROR, "config/hal: couldn't allocate name\n");
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
/* Check for duplicate devices */
|
||||
if (device_is_duplicate(config_info)) {
|
||||
LogMessage(X_WARNING,
|
||||
"config/hal: device %s already added. Ignoring.\n", name);
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
/* ok, grab options from hal.. iterate through all properties
|
||||
* and lets see if any of them are options that we can add */
|
||||
set = libhal_device_get_all_properties(hal_ctx, udi, &error);
|
||||
|
||||
if (!set) {
|
||||
LogMessage(X_ERROR,
|
||||
"config/hal: couldn't get property list for %s: %s (%s)\n",
|
||||
udi, error.name, error.message);
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
libhal_psi_init(&set_iter, set);
|
||||
while (libhal_psi_has_more(&set_iter)) {
|
||||
/* we are looking for supported keys.. extract and add to options */
|
||||
psi_key = libhal_psi_get_key(&set_iter);
|
||||
|
||||
if (psi_key) {
|
||||
|
||||
/* normal options first (input.x11_options.<propname>) */
|
||||
if (!strncasecmp
|
||||
(psi_key, LIBHAL_PROP_KEY, sizeof(LIBHAL_PROP_KEY) - 1)) {
|
||||
char *tmp;
|
||||
|
||||
/* only support strings for all values */
|
||||
tmp_val = get_prop_string(hal_ctx, udi, psi_key);
|
||||
|
||||
if (tmp_val) {
|
||||
|
||||
/* xkb needs special handling. HAL specs include
|
||||
* input.xkb.xyz options, but the x11-input.fdi specifies
|
||||
* input.x11_options.Xkbxyz options. By default, we use
|
||||
* the former, unless the specific X11 ones are specified.
|
||||
* Since we can't predict the order in which the keys
|
||||
* arrive, we need to store them.
|
||||
*/
|
||||
if ((tmp = strcasestr(psi_key, "xkb")) && strlen(tmp) >= 4) {
|
||||
if (!strcasecmp(&tmp[3], "layout")) {
|
||||
free(xkb_opts.layout);
|
||||
xkb_opts.layout = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(&tmp[3], "model")) {
|
||||
free(xkb_opts.model);
|
||||
xkb_opts.model = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(&tmp[3], "rules")) {
|
||||
free(xkb_opts.rules);
|
||||
xkb_opts.rules = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(&tmp[3], "variant")) {
|
||||
free(xkb_opts.variant);
|
||||
xkb_opts.variant = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(&tmp[3], "options")) {
|
||||
free(xkb_opts.options);
|
||||
xkb_opts.options = strdup(tmp_val);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* all others */
|
||||
input_options =
|
||||
input_option_new(input_options,
|
||||
psi_key + sizeof(LIBHAL_PROP_KEY) -
|
||||
1, tmp_val);
|
||||
free(tmp_val);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* server 1.4 had xkb_options as strlist. */
|
||||
if ((tmp = strcasestr(psi_key, "xkb")) &&
|
||||
(strlen(tmp) >= 4) &&
|
||||
(!strcasecmp(&tmp[3], "options")) &&
|
||||
(tmp_val =
|
||||
get_prop_string_array(hal_ctx, udi, psi_key))) {
|
||||
free(xkb_opts.options);
|
||||
xkb_opts.options = strdup(tmp_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strncasecmp
|
||||
(psi_key, LIBHAL_XKB_PROP_KEY,
|
||||
sizeof(LIBHAL_XKB_PROP_KEY) - 1)) {
|
||||
char *tmp;
|
||||
|
||||
/* only support strings for all values */
|
||||
tmp_val = get_prop_string(hal_ctx, udi, psi_key);
|
||||
|
||||
if (tmp_val && strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) {
|
||||
|
||||
tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1];
|
||||
|
||||
if (!strcasecmp(tmp, "layout")) {
|
||||
if (!xkb_opts.layout)
|
||||
xkb_opts.layout = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(tmp, "rules")) {
|
||||
if (!xkb_opts.rules)
|
||||
xkb_opts.rules = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(tmp, "variant")) {
|
||||
if (!xkb_opts.variant)
|
||||
xkb_opts.variant = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(tmp, "model")) {
|
||||
if (!xkb_opts.model)
|
||||
xkb_opts.model = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(tmp, "options")) {
|
||||
if (!xkb_opts.options)
|
||||
xkb_opts.options = strdup(tmp_val);
|
||||
}
|
||||
free(tmp_val);
|
||||
}
|
||||
else {
|
||||
/* server 1.4 had xkb options as strlist */
|
||||
tmp_val = get_prop_string_array(hal_ctx, udi, psi_key);
|
||||
if (tmp_val &&
|
||||
strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) {
|
||||
tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1];
|
||||
if (!strcasecmp(tmp, ".options") && (!xkb_opts.options))
|
||||
xkb_opts.options = strdup(tmp_val);
|
||||
}
|
||||
free(tmp_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* psi_key doesn't need to be freed */
|
||||
libhal_psi_next(&set_iter);
|
||||
}
|
||||
|
||||
/* Now add xkb options */
|
||||
if (xkb_opts.layout)
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_layout", xkb_opts.layout);
|
||||
if (xkb_opts.rules)
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_rules", xkb_opts.rules);
|
||||
if (xkb_opts.variant)
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_variant", xkb_opts.variant);
|
||||
if (xkb_opts.model)
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_model", xkb_opts.model);
|
||||
if (xkb_opts.options)
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_options", xkb_opts.options);
|
||||
input_options = input_option_new(input_options, "config_info", config_info);
|
||||
|
||||
/* this isn't an error, but how else do you output something that the user can see? */
|
||||
LogMessage(X_INFO, "config/hal: Adding input device %s\n", name);
|
||||
if ((rc = NewInputDeviceRequest(input_options, &attrs, &dev)) != Success) {
|
||||
LogMessage(X_ERROR, "config/hal: NewInputDeviceRequest failed (%d)\n",
|
||||
rc);
|
||||
dev = NULL;
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
unwind:
|
||||
if (set)
|
||||
libhal_free_property_set(set);
|
||||
free(path);
|
||||
free(driver);
|
||||
free(name);
|
||||
free(config_info);
|
||||
input_option_free_list(&input_options);
|
||||
|
||||
free(attrs.product);
|
||||
free(attrs.vendor);
|
||||
free(attrs.device);
|
||||
free(attrs.pnp_id);
|
||||
free(attrs.usb_id);
|
||||
if (attrs.tags) {
|
||||
char **tag = attrs.tags;
|
||||
|
||||
while (*tag) {
|
||||
free(*tag);
|
||||
tag++;
|
||||
}
|
||||
free(attrs.tags);
|
||||
}
|
||||
|
||||
free(xkb_opts.layout);
|
||||
free(xkb_opts.rules);
|
||||
free(xkb_opts.model);
|
||||
free(xkb_opts.variant);
|
||||
free(xkb_opts.options);
|
||||
|
||||
dbus_error_free(&error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_hook(void *data)
|
||||
{
|
||||
DBusError error;
|
||||
struct config_hal_info *info = data;
|
||||
|
||||
if (info->hal_ctx) {
|
||||
if (dbus_connection_get_is_connected(info->system_bus)) {
|
||||
dbus_error_init(&error);
|
||||
if (!libhal_ctx_shutdown(info->hal_ctx, &error))
|
||||
LogMessage(X_WARNING,
|
||||
"config/hal: disconnect_hook couldn't shut down context: %s (%s)\n",
|
||||
error.name, error.message);
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
libhal_ctx_free(info->hal_ctx);
|
||||
}
|
||||
|
||||
info->hal_ctx = NULL;
|
||||
info->system_bus = NULL;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
connect_and_register(DBusConnection * connection, struct config_hal_info *info)
|
||||
{
|
||||
DBusError error;
|
||||
char **devices;
|
||||
int num_devices, i;
|
||||
|
||||
if (info->hal_ctx)
|
||||
return TRUE; /* already registered, pretend we did something */
|
||||
|
||||
info->system_bus = connection;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
info->hal_ctx = libhal_ctx_new();
|
||||
if (!info->hal_ctx) {
|
||||
LogMessage(X_ERROR, "config/hal: couldn't create HAL context\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (!libhal_ctx_set_dbus_connection(info->hal_ctx, info->system_bus)) {
|
||||
LogMessage(X_ERROR,
|
||||
"config/hal: couldn't associate HAL context with bus\n");
|
||||
goto out_err;
|
||||
}
|
||||
if (!libhal_ctx_init(info->hal_ctx, &error)) {
|
||||
LogMessage(X_ERROR,
|
||||
"config/hal: couldn't initialise context: %s (%s)\n",
|
||||
error.name ? error.name : "unknown error",
|
||||
error.message ? error.message : "null");
|
||||
goto out_err;
|
||||
}
|
||||
if (!libhal_device_property_watch_all(info->hal_ctx, &error)) {
|
||||
LogMessage(X_ERROR,
|
||||
"config/hal: couldn't watch all properties: %s (%s)\n",
|
||||
error.name ? error.name : "unknown error",
|
||||
error.message ? error.message : "null");
|
||||
goto out_ctx;
|
||||
}
|
||||
libhal_ctx_set_device_added(info->hal_ctx, device_added);
|
||||
libhal_ctx_set_device_removed(info->hal_ctx, device_removed);
|
||||
|
||||
devices = libhal_find_device_by_capability(info->hal_ctx, "input",
|
||||
&num_devices, &error);
|
||||
/* FIXME: Get default devices if error is set. */
|
||||
if (dbus_error_is_set(&error)) {
|
||||
LogMessage(X_ERROR, "config/hal: couldn't find input device: %s (%s)\n",
|
||||
error.name ? error.name : "unknown error",
|
||||
error.message ? error.message : "null");
|
||||
goto out_ctx;
|
||||
}
|
||||
for (i = 0; i < num_devices; i++)
|
||||
device_added(info->hal_ctx, devices[i]);
|
||||
libhal_free_string_array(devices);
|
||||
|
||||
dbus_error_free(&error);
|
||||
|
||||
return TRUE;
|
||||
|
||||
out_ctx:
|
||||
dbus_error_free(&error);
|
||||
|
||||
if (!libhal_ctx_shutdown(info->hal_ctx, &error)) {
|
||||
LogMessage(X_WARNING,
|
||||
"config/hal: couldn't shut down context: %s (%s)\n",
|
||||
error.name ? error.name : "unknown error",
|
||||
error.message ? error.message : "null");
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
|
||||
out_err:
|
||||
dbus_error_free(&error);
|
||||
|
||||
if (info->hal_ctx) {
|
||||
libhal_ctx_free(info->hal_ctx);
|
||||
}
|
||||
|
||||
info->hal_ctx = NULL;
|
||||
info->system_bus = NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle NewOwnerChanged signals to deal with HAL startup at X server runtime.
|
||||
*
|
||||
* NewOwnerChanged is send once when HAL shuts down, and once again when it
|
||||
* comes back up. Message has three arguments, first is the name
|
||||
* (org.freedesktop.Hal), the second one is the old owner, third one is new
|
||||
* owner.
|
||||
*/
|
||||
static DBusHandlerResult
|
||||
ownerchanged_handler(DBusConnection * connection, DBusMessage * message,
|
||||
void *data)
|
||||
{
|
||||
int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
|
||||
if (dbus_message_is_signal(message,
|
||||
"org.freedesktop.DBus", "NameOwnerChanged")) {
|
||||
DBusError error;
|
||||
char *name, *old_owner, *new_owner;
|
||||
|
||||
dbus_error_init(&error);
|
||||
dbus_message_get_args(message, &error,
|
||||
DBUS_TYPE_STRING, &name,
|
||||
DBUS_TYPE_STRING, &old_owner,
|
||||
DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID);
|
||||
|
||||
if (dbus_error_is_set(&error)) {
|
||||
ErrorF
|
||||
("[config/hal] failed to get NameOwnerChanged args: %s (%s)\n",
|
||||
error.name, error.message);
|
||||
}
|
||||
else if (name && strcmp(name, "org.freedesktop.Hal") == 0) {
|
||||
|
||||
if (!old_owner || !strlen(old_owner)) {
|
||||
DebugF("[config/hal] HAL startup detected.\n");
|
||||
if (connect_and_register
|
||||
(connection, (struct config_hal_info *) data))
|
||||
dbus_connection_unregister_object_path(connection,
|
||||
"/org/freedesktop/DBus");
|
||||
else
|
||||
ErrorF("[config/hal] Failed to connect to HAL bus.\n");
|
||||
}
|
||||
|
||||
ret = DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a handler for the NameOwnerChanged signal.
|
||||
*/
|
||||
static BOOL
|
||||
listen_for_startup(DBusConnection * connection, void *data)
|
||||
{
|
||||
DBusObjectPathVTable vtable = {.message_function = ownerchanged_handler, };
|
||||
DBusError error;
|
||||
const char MATCH_RULE[] = "sender='org.freedesktop.DBus',"
|
||||
"interface='org.freedesktop.DBus',"
|
||||
"type='signal',"
|
||||
"path='/org/freedesktop/DBus'," "member='NameOwnerChanged'";
|
||||
int rc = FALSE;
|
||||
|
||||
dbus_error_init(&error);
|
||||
dbus_bus_add_match(connection, MATCH_RULE, &error);
|
||||
if (!dbus_error_is_set(&error)) {
|
||||
if (dbus_connection_register_object_path(connection,
|
||||
"/org/freedesktop/DBus",
|
||||
&vtable, data))
|
||||
rc = TRUE;
|
||||
else
|
||||
ErrorF("[config/hal] cannot register object path.\n");
|
||||
}
|
||||
else {
|
||||
ErrorF("[config/hal] couldn't add match rule: %s (%s)\n", error.name,
|
||||
error.message);
|
||||
ErrorF("[config/hal] cannot detect a HAL startup.\n");
|
||||
}
|
||||
|
||||
dbus_error_free(&error);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
connect_hook(DBusConnection * connection, void *data)
|
||||
{
|
||||
struct config_hal_info *info = data;
|
||||
|
||||
if (listen_for_startup(connection, data) &&
|
||||
connect_and_register(connection, info))
|
||||
dbus_connection_unregister_object_path(connection,
|
||||
"/org/freedesktop/DBus");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static struct config_hal_info hal_info;
|
||||
|
||||
static struct dbus_core_hook hook = {
|
||||
.connect = connect_hook,
|
||||
.disconnect = disconnect_hook,
|
||||
.data = &hal_info,
|
||||
};
|
||||
|
||||
int
|
||||
config_hal_init(void)
|
||||
{
|
||||
memset(&hal_info, 0, sizeof(hal_info));
|
||||
hal_info.system_bus = NULL;
|
||||
hal_info.hal_ctx = NULL;
|
||||
|
||||
if (!dbus_core_add_hook(&hook)) {
|
||||
LogMessage(X_ERROR, "config/hal: failed to add D-Bus hook\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* verbose message */
|
||||
LogMessageVerb(X_INFO, 7, "config/hal: initialized\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
config_hal_fini(void)
|
||||
{
|
||||
dbus_core_remove_hook(&hook);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
srcs_config = [
|
||||
'config.c',
|
||||
]
|
||||
|
||||
config_dep = [common_dep]
|
||||
|
||||
if build_dbus
|
||||
srcs_config += 'dbus-core.c'
|
||||
config_dep += dbus_dep
|
||||
endif
|
||||
|
||||
if build_hal
|
||||
srcs_config += 'hal.c'
|
||||
config_dep += hal_dep
|
||||
endif
|
||||
|
||||
if build_udev
|
||||
srcs_config += 'udev.c'
|
||||
config_dep += udev_dep
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'openbsd'
|
||||
srcs_config += 'wscons.c'
|
||||
endif
|
||||
|
||||
if build_xorg
|
||||
install_data('10-quirks.conf',
|
||||
install_dir: join_paths(get_option('datadir'), 'X11/xorg.conf.d'))
|
||||
endif
|
||||
|
||||
libxserver_config = static_library('libxserver_config',
|
||||
srcs_config,
|
||||
include_directories: inc,
|
||||
dependencies: config_dep,
|
||||
)
|
|
@ -0,0 +1,610 @@
|
|||
/*
|
||||
* Copyright © 2009 Julien Cristau
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Author: Julien Cristau <jcristau@debian.org>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <libudev.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "inputstr.h"
|
||||
#include "hotplug.h"
|
||||
#include "config-backends.h"
|
||||
#include "os.h"
|
||||
#include "globals.h"
|
||||
#include "systemd-logind.h"
|
||||
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#define UDEV_XKB_PROP_KEY "xkb"
|
||||
|
||||
#define LOG_PROPERTY(path, prop, val) \
|
||||
LogMessageVerb(X_INFO, 10, \
|
||||
"config/udev: getting property %s on %s " \
|
||||
"returned \"%s\"\n", \
|
||||
(prop), (path), (val) ? (val) : "(null)")
|
||||
#define LOG_SYSATTR(path, attr, val) \
|
||||
LogMessageVerb(X_INFO, 10, \
|
||||
"config/udev: getting attribute %s on %s " \
|
||||
"returned \"%s\"\n", \
|
||||
(attr), (path), (val) ? (val) : "(null)")
|
||||
|
||||
static struct udev_monitor *udev_monitor;
|
||||
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
static void
|
||||
config_udev_odev_setup_attribs(struct udev_device *udev_device, const char *path, const char *syspath,
|
||||
int major, int minor,
|
||||
config_odev_probe_proc_ptr probe_callback);
|
||||
#endif
|
||||
|
||||
static char itoa_buf[16];
|
||||
|
||||
static const char *itoa(int i)
|
||||
{
|
||||
snprintf(itoa_buf, sizeof(itoa_buf), "%d", i);
|
||||
return itoa_buf;
|
||||
}
|
||||
|
||||
static Bool
|
||||
check_seat(struct udev_device *udev_device)
|
||||
{
|
||||
const char *dev_seat;
|
||||
|
||||
dev_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
|
||||
if (!dev_seat)
|
||||
dev_seat = "seat0";
|
||||
|
||||
if (SeatId && strcmp(dev_seat, SeatId))
|
||||
return FALSE;
|
||||
|
||||
if (!SeatId && strcmp(dev_seat, "seat0"))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
device_added(struct udev_device *udev_device)
|
||||
{
|
||||
const char *path, *name = NULL;
|
||||
char *config_info = NULL;
|
||||
const char *syspath;
|
||||
const char *tags_prop;
|
||||
const char *key, *value, *tmp;
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
const char *subsys = NULL;
|
||||
#endif
|
||||
InputOption *input_options;
|
||||
InputAttributes attrs = { };
|
||||
DeviceIntPtr dev = NULL;
|
||||
struct udev_list_entry *set, *entry;
|
||||
struct udev_device *parent;
|
||||
int rc;
|
||||
dev_t devnum;
|
||||
|
||||
path = udev_device_get_devnode(udev_device);
|
||||
|
||||
syspath = udev_device_get_syspath(udev_device);
|
||||
|
||||
if (!path || !syspath)
|
||||
return;
|
||||
|
||||
if (!check_seat(udev_device))
|
||||
return;
|
||||
|
||||
devnum = udev_device_get_devnum(udev_device);
|
||||
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
subsys = udev_device_get_subsystem(udev_device);
|
||||
|
||||
if (subsys && !strcmp(subsys, "drm")) {
|
||||
const char *sysname = udev_device_get_sysname(udev_device);
|
||||
|
||||
if (strncmp(sysname, "card", 4) != 0)
|
||||
return;
|
||||
|
||||
/* Check for devices already added through xf86platformProbe() */
|
||||
if (xf86_find_platform_device_by_devnum(major(devnum), minor(devnum)))
|
||||
return;
|
||||
|
||||
LogMessage(X_INFO, "config/udev: Adding drm device (%s)\n", path);
|
||||
|
||||
config_udev_odev_setup_attribs(udev_device, path, syspath, major(devnum),
|
||||
minor(devnum), NewGPUDeviceRequest);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
value = udev_device_get_property_value(udev_device, "ID_INPUT");
|
||||
if (!value || !strcmp(value, "0")) {
|
||||
LogMessageVerb(X_INFO, 10,
|
||||
"config/udev: ignoring device %s without "
|
||||
"property ID_INPUT set\n", path);
|
||||
return;
|
||||
}
|
||||
|
||||
input_options = input_option_new(NULL, "_source", "server/udev");
|
||||
if (!input_options)
|
||||
return;
|
||||
|
||||
parent = udev_device_get_parent(udev_device);
|
||||
if (parent) {
|
||||
const char *ppath = udev_device_get_devnode(parent);
|
||||
const char *product = udev_device_get_property_value(parent, "PRODUCT");
|
||||
const char *pnp_id = udev_device_get_sysattr_value(parent, "id");
|
||||
unsigned int usb_vendor, usb_model;
|
||||
|
||||
name = udev_device_get_sysattr_value(parent, "name");
|
||||
LOG_SYSATTR(ppath, "name", name);
|
||||
if (!name) {
|
||||
name = udev_device_get_property_value(parent, "NAME");
|
||||
LOG_PROPERTY(ppath, "NAME", name);
|
||||
}
|
||||
|
||||
/* construct USB ID in lowercase hex - "0000:ffff" */
|
||||
if (product &&
|
||||
sscanf(product, "%*x/%4x/%4x/%*x", &usb_vendor, &usb_model) == 2) {
|
||||
char *usb_id;
|
||||
if (asprintf(&usb_id, "%04x:%04x", usb_vendor, usb_model)
|
||||
== -1)
|
||||
usb_id = NULL;
|
||||
else
|
||||
LOG_PROPERTY(ppath, "PRODUCT", product);
|
||||
attrs.usb_id = usb_id;
|
||||
}
|
||||
|
||||
while (!pnp_id && (parent = udev_device_get_parent(parent))) {
|
||||
pnp_id = udev_device_get_sysattr_value(parent, "id");
|
||||
if (!pnp_id)
|
||||
continue;
|
||||
|
||||
attrs.pnp_id = strdup(pnp_id);
|
||||
ppath = udev_device_get_devnode(parent);
|
||||
LOG_SYSATTR(ppath, "id", pnp_id);
|
||||
}
|
||||
|
||||
}
|
||||
if (!name)
|
||||
name = "(unnamed)";
|
||||
else
|
||||
attrs.product = strdup(name);
|
||||
input_options = input_option_new(input_options, "name", name);
|
||||
input_options = input_option_new(input_options, "path", path);
|
||||
input_options = input_option_new(input_options, "device", path);
|
||||
input_options = input_option_new(input_options, "major", itoa(major(devnum)));
|
||||
input_options = input_option_new(input_options, "minor", itoa(minor(devnum)));
|
||||
if (path)
|
||||
attrs.device = strdup(path);
|
||||
|
||||
tags_prop = udev_device_get_property_value(udev_device, "ID_INPUT.tags");
|
||||
LOG_PROPERTY(path, "ID_INPUT.tags", tags_prop);
|
||||
attrs.tags = xstrtokenize(tags_prop, ",");
|
||||
|
||||
if (asprintf(&config_info, "udev:%s", syspath) == -1) {
|
||||
config_info = NULL;
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
if (device_is_duplicate(config_info)) {
|
||||
LogMessage(X_WARNING, "config/udev: device %s already added. "
|
||||
"Ignoring.\n", name);
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
set = udev_device_get_properties_list_entry(udev_device);
|
||||
udev_list_entry_foreach(entry, set) {
|
||||
key = udev_list_entry_get_name(entry);
|
||||
if (!key)
|
||||
continue;
|
||||
value = udev_list_entry_get_value(entry);
|
||||
if (!strncasecmp(key, UDEV_XKB_PROP_KEY, sizeof(UDEV_XKB_PROP_KEY) - 1)) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1;
|
||||
if (!strcasecmp(tmp, "rules"))
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_rules", value);
|
||||
else if (!strcasecmp(tmp, "layout"))
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_layout", value);
|
||||
else if (!strcasecmp(tmp, "variant"))
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_variant", value);
|
||||
else if (!strcasecmp(tmp, "model"))
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_model", value);
|
||||
else if (!strcasecmp(tmp, "options"))
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_options", value);
|
||||
}
|
||||
else if (!strcmp(key, "ID_VENDOR")) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
attrs.vendor = strdup(value);
|
||||
} else if (!strncmp(key, "ID_INPUT_", 9)) {
|
||||
const struct pfmap {
|
||||
const char *property;
|
||||
unsigned int flag;
|
||||
} map[] = {
|
||||
{ "ID_INPUT_KEY", ATTR_KEY },
|
||||
{ "ID_INPUT_KEYBOARD", ATTR_KEYBOARD },
|
||||
{ "ID_INPUT_MOUSE", ATTR_POINTER },
|
||||
{ "ID_INPUT_JOYSTICK", ATTR_JOYSTICK },
|
||||
{ "ID_INPUT_TABLET", ATTR_TABLET },
|
||||
{ "ID_INPUT_TABLET_PAD", ATTR_TABLET_PAD },
|
||||
{ "ID_INPUT_TOUCHPAD", ATTR_TOUCHPAD },
|
||||
{ "ID_INPUT_TOUCHSCREEN", ATTR_TOUCHSCREEN },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
/* Anything but the literal string "0" is considered a
|
||||
* boolean true. The empty string isn't a thing with udev
|
||||
* properties anyway */
|
||||
if (value && strcmp(value, "0")) {
|
||||
const struct pfmap *m = map;
|
||||
|
||||
while (m->property != NULL) {
|
||||
if (!strcmp(m->property, key)) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
attrs.flags |= m->flag;
|
||||
}
|
||||
m++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input_options = input_option_new(input_options, "config_info", config_info);
|
||||
|
||||
/* Default setting needed for non-seat0 seats */
|
||||
if (ServerIsNotSeat0())
|
||||
input_options = input_option_new(input_options, "GrabDevice", "on");
|
||||
|
||||
LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n",
|
||||
name, path);
|
||||
rc = NewInputDeviceRequest(input_options, &attrs, &dev);
|
||||
if (rc != Success)
|
||||
goto unwind;
|
||||
|
||||
unwind:
|
||||
free(config_info);
|
||||
input_option_free_list(&input_options);
|
||||
|
||||
free(attrs.usb_id);
|
||||
free(attrs.pnp_id);
|
||||
free(attrs.product);
|
||||
free(attrs.device);
|
||||
free(attrs.vendor);
|
||||
if (attrs.tags) {
|
||||
char **tag = attrs.tags;
|
||||
|
||||
while (*tag) {
|
||||
free(*tag);
|
||||
tag++;
|
||||
}
|
||||
free(attrs.tags);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
device_removed(struct udev_device *device)
|
||||
{
|
||||
char *value;
|
||||
const char *syspath = udev_device_get_syspath(device);
|
||||
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
const char *subsys = udev_device_get_subsystem(device);
|
||||
|
||||
if (subsys && !strcmp(subsys, "drm")) {
|
||||
const char *sysname = udev_device_get_sysname(device);
|
||||
const char *path = udev_device_get_devnode(device);
|
||||
dev_t devnum = udev_device_get_devnum(device);
|
||||
|
||||
if ((strncmp(sysname,"card", 4) != 0) || (path == NULL))
|
||||
return;
|
||||
|
||||
LogMessage(X_INFO, "config/udev: removing GPU device %s %s\n",
|
||||
syspath, path);
|
||||
config_udev_odev_setup_attribs(device, path, syspath, major(devnum),
|
||||
minor(devnum), DeleteGPUDeviceRequest);
|
||||
/* Retry vtenter after a drm node removal */
|
||||
systemd_logind_vtenter();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (asprintf(&value, "udev:%s", syspath) == -1)
|
||||
return;
|
||||
|
||||
remove_devices("udev", value);
|
||||
|
||||
free(value);
|
||||
}
|
||||
|
||||
static void
|
||||
socket_handler(int fd, int ready, void *data)
|
||||
{
|
||||
struct udev_device *udev_device;
|
||||
const char *action;
|
||||
|
||||
input_lock();
|
||||
udev_device = udev_monitor_receive_device(udev_monitor);
|
||||
if (!udev_device) {
|
||||
input_unlock();
|
||||
return;
|
||||
}
|
||||
action = udev_device_get_action(udev_device);
|
||||
if (action) {
|
||||
if (!strcmp(action, "add")) {
|
||||
device_removed(udev_device);
|
||||
device_added(udev_device);
|
||||
} else if (!strcmp(action, "change")) {
|
||||
/* ignore change for the drm devices */
|
||||
const char *subsys = udev_device_get_subsystem(udev_device);
|
||||
|
||||
if (subsys && strcmp(subsys, "drm")) {
|
||||
device_removed(udev_device);
|
||||
device_added(udev_device);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(action, "remove"))
|
||||
device_removed(udev_device);
|
||||
}
|
||||
udev_device_unref(udev_device);
|
||||
input_unlock();
|
||||
}
|
||||
|
||||
int
|
||||
config_udev_pre_init(void)
|
||||
{
|
||||
struct udev *udev;
|
||||
|
||||
udev = udev_new();
|
||||
if (!udev)
|
||||
return 0;
|
||||
|
||||
udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
|
||||
if (!udev_monitor)
|
||||
return 0;
|
||||
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input",
|
||||
NULL);
|
||||
/* For Wacom serial devices */
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL);
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
/* For output GPU devices */
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "drm", NULL);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UDEV_MONITOR_FILTER_ADD_MATCH_TAG
|
||||
if (ServerIsNotSeat0())
|
||||
udev_monitor_filter_add_match_tag(udev_monitor, SeatId);
|
||||
#endif
|
||||
if (udev_monitor_enable_receiving(udev_monitor)) {
|
||||
ErrorF("config/udev: failed to bind the udev monitor\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
config_udev_init(void)
|
||||
{
|
||||
struct udev *udev;
|
||||
struct udev_enumerate *enumerate;
|
||||
struct udev_list_entry *devices, *device;
|
||||
|
||||
udev = udev_monitor_get_udev(udev_monitor);
|
||||
enumerate = udev_enumerate_new(udev);
|
||||
if (!enumerate)
|
||||
return 0;
|
||||
|
||||
udev_enumerate_add_match_subsystem(enumerate, "input");
|
||||
udev_enumerate_add_match_subsystem(enumerate, "tty");
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
udev_enumerate_add_match_subsystem(enumerate, "drm");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
|
||||
if (ServerIsNotSeat0())
|
||||
udev_enumerate_add_match_tag(enumerate, SeatId);
|
||||
#endif
|
||||
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
devices = udev_enumerate_get_list_entry(enumerate);
|
||||
udev_list_entry_foreach(device, devices) {
|
||||
const char *syspath = udev_list_entry_get_name(device);
|
||||
struct udev_device *udev_device =
|
||||
udev_device_new_from_syspath(udev, syspath);
|
||||
|
||||
/* Device might be gone by the time we try to open it */
|
||||
if (!udev_device)
|
||||
continue;
|
||||
|
||||
device_added(udev_device);
|
||||
udev_device_unref(udev_device);
|
||||
}
|
||||
udev_enumerate_unref(enumerate);
|
||||
|
||||
SetNotifyFd(udev_monitor_get_fd(udev_monitor), socket_handler, X_NOTIFY_READ, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
config_udev_fini(void)
|
||||
{
|
||||
struct udev *udev;
|
||||
|
||||
if (!udev_monitor)
|
||||
return;
|
||||
|
||||
udev = udev_monitor_get_udev(udev_monitor);
|
||||
|
||||
RemoveNotifyFd(udev_monitor_get_fd(udev_monitor));
|
||||
udev_monitor_unref(udev_monitor);
|
||||
udev_monitor = NULL;
|
||||
udev_unref(udev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
|
||||
/* Find the last occurrence of the needle in haystack */
|
||||
static char *strrstr(const char *haystack, const char *needle)
|
||||
{
|
||||
char *prev, *last, *tmp;
|
||||
|
||||
prev = strstr(haystack, needle);
|
||||
if (!prev)
|
||||
return NULL;
|
||||
|
||||
last = prev;
|
||||
tmp = prev + 1;
|
||||
|
||||
while (tmp) {
|
||||
last = strstr(tmp, needle);
|
||||
if (!last)
|
||||
return prev;
|
||||
else {
|
||||
prev = last;
|
||||
tmp = prev + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
/* For certain devices udev does not create ID_PATH entry (which is presumably a bug
|
||||
* in udev). We work around that by implementing a minimal ID_PATH calculator
|
||||
* ourselves along the same logic that udev uses. This works only for the case of
|
||||
* a PCI device being directly connected to a PCI bus, but it will cover most end
|
||||
* users with e.g. a new laptop which only has beta hardware driver support.
|
||||
* See https://gitlab.freedesktop.org/xorg/xserver/-/issues/993 */
|
||||
static char*
|
||||
config_udev_get_fallback_bus_id(struct udev_device *udev_device)
|
||||
{
|
||||
const char *sysname;
|
||||
char *busid;
|
||||
|
||||
udev_device = udev_device_get_parent(udev_device);
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
|
||||
if (strcmp(udev_device_get_subsystem(udev_device), "pci") != 0)
|
||||
return NULL;
|
||||
|
||||
sysname = udev_device_get_sysname(udev_device);
|
||||
busid = XNFalloc(strlen(sysname) + 5);
|
||||
busid[0] = '\0';
|
||||
strcat(busid, "pci:");
|
||||
strcat(busid, sysname);
|
||||
|
||||
return busid;
|
||||
}
|
||||
|
||||
static void
|
||||
config_udev_odev_setup_attribs(struct udev_device *udev_device, const char *path, const char *syspath,
|
||||
int major, int minor,
|
||||
config_odev_probe_proc_ptr probe_callback)
|
||||
{
|
||||
struct OdevAttributes *attribs = config_odev_allocate_attributes();
|
||||
const char *value, *str;
|
||||
|
||||
attribs->path = XNFstrdup(path);
|
||||
attribs->syspath = XNFstrdup(syspath);
|
||||
attribs->major = major;
|
||||
attribs->minor = minor;
|
||||
|
||||
value = udev_device_get_property_value(udev_device, "ID_PATH");
|
||||
if (value && (str = strrstr(value, "pci-"))) {
|
||||
value = str;
|
||||
|
||||
if ((str = strstr(value, "usb-")))
|
||||
value = str;
|
||||
|
||||
attribs->busid = XNFstrdup(value);
|
||||
attribs->busid[3] = ':';
|
||||
}
|
||||
|
||||
if (!value)
|
||||
attribs->busid = config_udev_get_fallback_bus_id(udev_device);
|
||||
|
||||
/* ownership of attribs is passed to probe layer */
|
||||
probe_callback(attribs);
|
||||
}
|
||||
|
||||
void
|
||||
config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback)
|
||||
{
|
||||
struct udev *udev;
|
||||
struct udev_enumerate *enumerate;
|
||||
struct udev_list_entry *devices, *device;
|
||||
|
||||
udev = udev_monitor_get_udev(udev_monitor);
|
||||
enumerate = udev_enumerate_new(udev);
|
||||
if (!enumerate)
|
||||
return;
|
||||
|
||||
udev_enumerate_add_match_subsystem(enumerate, "drm");
|
||||
udev_enumerate_add_match_sysname(enumerate, "card[0-9]*");
|
||||
#ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
|
||||
if (ServerIsNotSeat0())
|
||||
udev_enumerate_add_match_tag(enumerate, SeatId);
|
||||
#endif
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
devices = udev_enumerate_get_list_entry(enumerate);
|
||||
udev_list_entry_foreach(device, devices) {
|
||||
const char *syspath = udev_list_entry_get_name(device);
|
||||
struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath);
|
||||
const char *path = udev_device_get_devnode(udev_device);
|
||||
const char *sysname = udev_device_get_sysname(udev_device);
|
||||
dev_t devnum = udev_device_get_devnum(udev_device);
|
||||
const char *subsys = udev_device_get_subsystem(udev_device);
|
||||
|
||||
if (!path || !syspath || !subsys)
|
||||
goto no_probe;
|
||||
else if (strcmp(subsys, "drm") != 0)
|
||||
goto no_probe;
|
||||
else if (strncmp(sysname, "card", 4) != 0)
|
||||
goto no_probe;
|
||||
else if (!check_seat(udev_device))
|
||||
goto no_probe;
|
||||
|
||||
config_udev_odev_setup_attribs(udev_device, path, syspath, major(devnum),
|
||||
minor(devnum), probe_callback);
|
||||
no_probe:
|
||||
udev_device_unref(udev_device);
|
||||
}
|
||||
udev_enumerate_unref(enumerate);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Matthieu Herrb
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <dev/wscons/wsconsio.h>
|
||||
#include <dev/wscons/wsksymdef.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "inputstr.h"
|
||||
#include "os.h"
|
||||
#include "config-backends.h"
|
||||
|
||||
#define WSCONS_KBD_DEVICE "/dev/wskbd"
|
||||
#define WSCONS_MOUSE_PREFIX "/dev/wsmouse"
|
||||
|
||||
#define KB_OVRENC \
|
||||
{ KB_UK, "gb" }, \
|
||||
{ KB_SV, "se" }, \
|
||||
{ KB_SG, "ch" }, \
|
||||
{ KB_SF, "ch" }, \
|
||||
{ KB_LA, "latam" }, \
|
||||
{ KB_CF, "ca" }
|
||||
|
||||
struct nameint {
|
||||
int val;
|
||||
char *name;
|
||||
} kbdenc[] = {
|
||||
KB_OVRENC,
|
||||
KB_ENCTAB,
|
||||
{0}
|
||||
};
|
||||
|
||||
struct nameint kbdvar[] = {
|
||||
{KB_NODEAD | KB_SG, "de_nodeadkeys"},
|
||||
{KB_NODEAD | KB_SF, "fr_nodeadkeys"},
|
||||
{KB_SF, "fr"},
|
||||
{KB_DVORAK | KB_CF, "fr-dvorak"},
|
||||
{KB_DVORAK | KB_FR, "bepo"},
|
||||
{KB_DVORAK, "dvorak"},
|
||||
{KB_CF, "fr-legacy"},
|
||||
{KB_NODEAD, "nodeadkeys"},
|
||||
{0}
|
||||
};
|
||||
|
||||
struct nameint kbdopt[] = {
|
||||
{KB_SWAPCTRLCAPS, "ctrl:swapcaps"},
|
||||
{0}
|
||||
};
|
||||
|
||||
struct nameint kbdmodel[] = {
|
||||
{WSKBD_TYPE_ZAURUS, "zaurus"},
|
||||
{0}
|
||||
};
|
||||
|
||||
static void
|
||||
wscons_add_keyboard(void)
|
||||
{
|
||||
InputAttributes attrs = { };
|
||||
DeviceIntPtr dev = NULL;
|
||||
InputOption *input_options = NULL;
|
||||
char *config_info = NULL;
|
||||
int fd, i, rc;
|
||||
unsigned int type;
|
||||
kbd_t wsenc = 0;
|
||||
|
||||
/* Find keyboard configuration */
|
||||
fd = open(WSCONS_KBD_DEVICE, O_RDWR | O_NONBLOCK | O_EXCL);
|
||||
if (fd == -1) {
|
||||
LogMessage(X_ERROR, "wskbd: open %s: %s\n",
|
||||
WSCONS_KBD_DEVICE, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (ioctl(fd, WSKBDIO_GETENCODING, &wsenc) == -1) {
|
||||
LogMessage(X_WARNING, "wskbd: ioctl(WSKBDIO_GETENCODING) "
|
||||
"failed: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
if (ioctl(fd, WSKBDIO_GTYPE, &type) == -1) {
|
||||
LogMessage(X_WARNING, "wskbd: ioctl(WSKBDIO_GTYPE) "
|
||||
"failed: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
input_options = input_option_new(input_options, "_source", "server/wscons");
|
||||
if (input_options == NULL)
|
||||
return;
|
||||
|
||||
LogMessage(X_INFO, "config/wscons: checking input device %s\n",
|
||||
WSCONS_KBD_DEVICE);
|
||||
input_options = input_option_new(input_options, "name", WSCONS_KBD_DEVICE);
|
||||
input_options = input_option_new(input_options, "driver", "kbd");
|
||||
|
||||
config_info = Xprintf("wscons:%s", WSCONS_KBD_DEVICE);
|
||||
if (!config_info)
|
||||
goto unwind;
|
||||
if (KB_ENCODING(wsenc) == KB_USER) {
|
||||
/* Ignore wscons "user" layout */
|
||||
LogMessageVerb(X_INFO, 3, "wskbd: ignoring \"user\" layout\n");
|
||||
goto kbd_config_done;
|
||||
}
|
||||
for (i = 0; kbdenc[i].val; i++)
|
||||
if (KB_ENCODING(wsenc) == kbdenc[i].val) {
|
||||
LogMessageVerb(X_INFO, 3, "wskbd: using layout %s\n",
|
||||
kbdenc[i].name);
|
||||
input_options = input_option_new(input_options,
|
||||
"xkb_layout", kbdenc[i].name);
|
||||
break;
|
||||
}
|
||||
for (i = 0; kbdvar[i].val; i++)
|
||||
if (wsenc == kbdvar[i].val || KB_VARIANT(wsenc) == kbdvar[i].val) {
|
||||
LogMessageVerb(X_INFO, 3, "wskbd: using variant %s\n",
|
||||
kbdvar[i].name);
|
||||
input_options = input_option_new(input_options,
|
||||
"xkb_variant", kbdvar[i].name);
|
||||
break;
|
||||
}
|
||||
for (i = 0; kbdopt[i].val; i++)
|
||||
if (KB_VARIANT(wsenc) == kbdopt[i].val) {
|
||||
LogMessageVerb(X_INFO, 3, "wskbd: using option %s\n",
|
||||
kbdopt[i].name);
|
||||
input_options = input_option_new(input_options,
|
||||
"xkb_options", kbdopt[i].name);
|
||||
break;
|
||||
}
|
||||
for (i = 0; kbdmodel[i].val; i++)
|
||||
if (type == kbdmodel[i].val) {
|
||||
LogMessageVerb(X_INFO, 3, "wskbd: using model %s\n",
|
||||
kbdmodel[i].name);
|
||||
input_options = input_option_new(input_options,
|
||||
"xkb_model", kbdmodel[i].name);
|
||||
break;
|
||||
}
|
||||
|
||||
kbd_config_done:
|
||||
attrs.flags |= ATTR_KEY | ATTR_KEYBOARD;
|
||||
rc = NewInputDeviceRequest(input_options, &attrs, &dev);
|
||||
if (rc != Success)
|
||||
goto unwind;
|
||||
|
||||
for (; dev; dev = dev->next) {
|
||||
free(dev->config_info);
|
||||
dev->config_info = strdup(config_info);
|
||||
}
|
||||
unwind:
|
||||
input_option_free_list(&input_options);
|
||||
}
|
||||
|
||||
static void
|
||||
wscons_add_pointer(const char *path, const char *driver, int flags)
|
||||
{
|
||||
InputAttributes attrs = { };
|
||||
DeviceIntPtr dev = NULL;
|
||||
InputOption *input_options = NULL;
|
||||
char *config_info = NULL;
|
||||
int rc;
|
||||
|
||||
config_info = Xprintf("wscons:%s", path);
|
||||
if (!config_info)
|
||||
return;
|
||||
|
||||
input_options = input_option_new(input_options, "_source", "server/wscons");
|
||||
if (input_options == NULL)
|
||||
return;
|
||||
|
||||
input_options = input_option_new(input_options, "name", strdup(path));
|
||||
input_options = input_option_new(input_options, "driver", strdup(driver));
|
||||
input_options = input_option_new(input_options, "device", strdup(path));
|
||||
LogMessage(X_INFO, "config/wscons: checking input device %s\n", path);
|
||||
attrs.flags |= flags;
|
||||
rc = NewInputDeviceRequest(input_options, &attrs, &dev);
|
||||
if (rc != Success)
|
||||
goto unwind;
|
||||
|
||||
for (; dev; dev = dev->next) {
|
||||
free(dev->config_info);
|
||||
dev->config_info = strdup(config_info);
|
||||
}
|
||||
unwind:
|
||||
input_option_free_list(&input_options);
|
||||
}
|
||||
|
||||
static void
|
||||
wscons_add_pointers(void)
|
||||
{
|
||||
char devname[256];
|
||||
int fd, i, wsmouse_type;
|
||||
|
||||
/* Check pointing devices */
|
||||
for (i = 0; i < 4; i++) {
|
||||
snprintf(devname, sizeof(devname), "%s%d", WSCONS_MOUSE_PREFIX, i);
|
||||
LogMessageVerb(X_INFO, 10, "wsmouse: checking %s\n", devname);
|
||||
fd = open_device(devnamem O_RDWR | O_NONBLOCK | O_EXCL);
|
||||
if (fd == -1) {
|
||||
LogMessageVerb(X_WARNING, 10, "%s: %s\n", devname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (ioctl(fd, WSMOUSEIO_GTYPE, &wsmouse_type) != 0) {
|
||||
LogMessageVerb(X_WARNING, 10,
|
||||
"%s: WSMOUSEIO_GTYPE failed\n", devname);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
close(fd);
|
||||
switch (wsmouse_type) {
|
||||
case WSMOUSE_TYPE_SYNAPTICS:
|
||||
wscons_add_pointer(devname, "synaptics", ATTR_TOUCHPAD);
|
||||
break;
|
||||
case WSMOUSE_TYPE_TPANEL:
|
||||
wscons_add_pointer(devname, "ws", ATTR_TOUCHSCREEN);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Add a default entry catching all other mux elements as "mouse" */
|
||||
wscons_add_pointer(WSCONS_MOUSE_PREFIX, "mouse", ATTR_POINTER);
|
||||
}
|
||||
|
||||
int
|
||||
config_wscons_init(void)
|
||||
{
|
||||
wscons_add_keyboard();
|
||||
wscons_add_pointers();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
config_wscons_fini(void)
|
||||
{
|
||||
/* Not much to do ? */
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<deviceinfo version="0.2">
|
||||
<device>
|
||||
|
||||
<!-- The way this works:
|
||||
|
||||
Match against some input device (see the HAL specification for more
|
||||
information), and then merge in keys, which you can use to specify
|
||||
the configuration similar to the way you would in xorg.conf. You will
|
||||
need to restart HAL after making changes. If you are having issues,
|
||||
starting X with the -logverbose 7 flag may yield useful information.
|
||||
|
||||
Keys Supported:
|
||||
|
||||
Key "input.x11_driver" (string)
|
||||
This specifies the driver to use. You MUST specify this option,
|
||||
or a driver will not be loaded and the rest will be ignored by
|
||||
Xorg
|
||||
|
||||
Key "input.x11_options.<option name>" (string)
|
||||
This allows you to specify arbitrary options to pass to the driver.
|
||||
Anything you would normally specify in xorg.conf goes here. So, for
|
||||
option "Mode" in xorg.conf, you would specify the key name of
|
||||
"input.x11_options.Mode".
|
||||
|
||||
Do not specify "input.x11_options.Device" since "input.device"
|
||||
will be used automatically.
|
||||
|
||||
You MUST specify all options as strings, otherwise the server will
|
||||
ignore them.
|
||||
|
||||
Legacy Keys
|
||||
"input.xkb.rules"
|
||||
"input.xkb.model"
|
||||
"input.xkb.layout"
|
||||
"input.xkb.variant"
|
||||
"input.xkb.options"
|
||||
|
||||
These keys are deprecated. Use these instead:
|
||||
"input.x11_options.XkbRules"
|
||||
"input.x11_options.XkbModel"
|
||||
"input.x11_options.XkbLayout"
|
||||
"input.x11_options.XkbVariant"
|
||||
"input.x11_options.XkbOptions"
|
||||
|
||||
See the evdev documentation for more information.
|
||||
|
||||
FIXME: Support tablets too.
|
||||
TODO: I think its fixed, can't test
|
||||
|
||||
-->
|
||||
|
||||
<match key="info.capabilities" contains="input.mouse">
|
||||
<merge key="input.x11_driver" type="string">mouse</merge>
|
||||
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
|
||||
string="Linux">
|
||||
<merge key="input.x11_driver" type="string">evdev</merge>
|
||||
</match>
|
||||
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
|
||||
string="SunOS">
|
||||
<match key="input.device" contains="usb">
|
||||
<merge key="input.x11_options.StreamsModule" type="string">usbms</merge>
|
||||
<merge key="input.x11_options.Protocol" type="string">VUID</merge>
|
||||
</match>
|
||||
</match>
|
||||
</match>
|
||||
|
||||
<match key="info.capabilities" contains="input.keys">
|
||||
<merge key="input.x11_options.XkbRules" type="string">base</merge>
|
||||
|
||||
<!-- If we're using Linux, we use evdev by default (falling back to
|
||||
kbd otherwise). -->
|
||||
<merge key="input.x11_driver" type="string">kbd</merge>
|
||||
<merge key="input.x11_options.XkbModel" type="string">pc105</merge>
|
||||
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
|
||||
string="Linux">
|
||||
<merge key="input.x11_driver" type="string">evdev</merge>
|
||||
<merge key="input.x11_options.XkbModel" type="string">evdev</merge>
|
||||
</match>
|
||||
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
|
||||
string="SunOS">
|
||||
<match key="input.device" contains="usb">
|
||||
<merge key="input.x11_options.StreamsModule" type="string">usbkbm</merge>
|
||||
<merge key="input.x11_options.Protocol" type="string">VUID</merge>
|
||||
</match>
|
||||
</match>
|
||||
|
||||
<merge key="input.x11_options.XkbLayout" type="string">us</merge>
|
||||
|
||||
<merge key="input.x11_options.XkbVariant" type="string" />
|
||||
</match>
|
||||
</device>
|
||||
</deviceinfo>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
|||
noinst_LTLIBRARIES = libdamageext.la
|
||||
|
||||
AM_CFLAGS = $(DIX_CFLAGS)
|
||||
|
||||
libdamageext_la_SOURCES = \
|
||||
damageext.c \
|
||||
damageextint.h
|
|
@ -561,7 +561,11 @@ static int _X_COLD
|
|||
SProcDamageDispatch(ClientPtr client)
|
||||
{
|
||||
REQUEST(xDamageReq);
|
||||
if (stuff->damageReqType >= XDamageNumberRequests)
|
||||
DamageClientPtr pDamageClient = GetDamageClient(client);
|
||||
|
||||
if (pDamageClient->major_version >= ARRAY_SIZE(version_requests))
|
||||
return BadRequest;
|
||||
if (stuff->damageReqType > version_requests[pDamageClient->major_version])
|
||||
return BadRequest;
|
||||
return (*SProcDamageVector[stuff->damageReqType]) (client);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
noinst_LTLIBRARIES = libdbe.la
|
||||
|
||||
AM_CFLAGS = $(DIX_CFLAGS)
|
||||
|
||||
if XORG
|
||||
sdk_HEADERS = dbestruct.h
|
||||
endif
|
||||
|
||||
libdbe_la_SOURCES = \
|
||||
dbe.c \
|
||||
midbe.c \
|
||||
midbe.h
|
|
@ -12,3 +12,7 @@ libxserver_dbe = static_library('libxserver_dbe',
|
|||
include_directories: inc,
|
||||
dependencies: common_dep,
|
||||
)
|
||||
|
||||
if build_xorg
|
||||
install_data(hdrs_dbe, install_dir: xorgsdkdir)
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
noinst_LTLIBRARIES = libdix.la libmain.la
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
AM_CFLAGS = $(DIX_CFLAGS)
|
||||
|
||||
libmain_la_SOURCES = \
|
||||
stubmain.c
|
||||
|
||||
libdix_la_SOURCES = \
|
||||
atom.c \
|
||||
colormap.c \
|
||||
cursor.c \
|
||||
devices.c \
|
||||
dispatch.c \
|
||||
dispatch.h \
|
||||
dixfonts.c \
|
||||
main.c \
|
||||
dixutils.c \
|
||||
enterleave.c \
|
||||
enterleave.h \
|
||||
events.c \
|
||||
eventconvert.c \
|
||||
extension.c \
|
||||
gc.c \
|
||||
getevents.c \
|
||||
gestures.c \
|
||||
globals.c \
|
||||
glyphcurs.c \
|
||||
grabs.c \
|
||||
initatoms.c \
|
||||
inpututils.c \
|
||||
pixmap.c \
|
||||
privates.c \
|
||||
property.c \
|
||||
ptrveloc.c \
|
||||
region.c \
|
||||
registry.c \
|
||||
resource.c \
|
||||
selection.c \
|
||||
swaprep.c \
|
||||
swapreq.c \
|
||||
tables.c \
|
||||
touch.c \
|
||||
window.c
|
||||
|
||||
EXTRA_DIST = buildatoms BuiltInAtoms
|
||||
|
||||
# Install list of protocol names
|
||||
miscconfigdir = $(SERVER_MISC_CONFIG_PATH)
|
||||
dist_miscconfig_DATA = protocol.txt
|
||||
|
||||
if SPECIAL_DTRACE_OBJECTS
|
||||
# Generate dtrace object code for probes in libdix
|
||||
dtrace-dix.o: $(top_srcdir)/include/Xserver.d libdix.la
|
||||
$(AM_V_GEN)$(DTRACE) -G -C -o $@ -s $(top_srcdir)/include/Xserver.d $(am_libdix_la_OBJECTS:%.lo=.libs/%.o)
|
||||
|
||||
noinst_PROGRAMS = dix.O
|
||||
|
||||
dix_O_SOURCES =
|
||||
dix.O: dtrace-dix.o libdix.la
|
||||
$(AM_V_GEN)ld -r -o $@ $(am_libdix_la_OBJECTS:%.lo=.libs/%.o)
|
||||
endif
|
|
@ -458,6 +458,7 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent)
|
|||
return FALSE;
|
||||
|
||||
TouchEndPhysicallyActiveTouches(dev);
|
||||
GestureEndActiveGestures(dev);
|
||||
ReleaseButtonsAndKeys(dev);
|
||||
SyncRemoveDeviceIdleTime(dev->idle_counter);
|
||||
dev->idle_counter = NULL;
|
||||
|
@ -1670,6 +1671,32 @@ InitTouchClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up gesture capabilities on @device.
|
||||
*
|
||||
* @max_touches The maximum number of simultaneous touches, or 0 for unlimited.
|
||||
*/
|
||||
Bool
|
||||
InitGestureClassDeviceStruct(DeviceIntPtr device, unsigned int max_touches)
|
||||
{
|
||||
GestureClassPtr g;
|
||||
|
||||
BUG_RETURN_VAL(device == NULL, FALSE);
|
||||
BUG_RETURN_VAL(device->gesture != NULL, FALSE);
|
||||
|
||||
g = calloc(1, sizeof(*g));
|
||||
if (!g)
|
||||
return FALSE;
|
||||
|
||||
g->sourceid = device->id;
|
||||
g->max_touches = max_touches;
|
||||
GestureInitGestureInfo(&g->gesture);
|
||||
|
||||
device->gesture = g;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the given buffer contains elements between low (inclusive) and
|
||||
* high (inclusive) only.
|
||||
|
|
|
@ -128,6 +128,7 @@ int ProcInitialConnection();
|
|||
#include "inputstr.h"
|
||||
#include "xkbsrv.h"
|
||||
#include "client.h"
|
||||
#include "xfixesint.h"
|
||||
|
||||
#ifdef XSERVER_DTRACE
|
||||
#include "registry.h"
|
||||
|
@ -164,6 +165,7 @@ static int nextFreeClientID; /* always MIN free client ID */
|
|||
static int nClients; /* number of authorized clients */
|
||||
|
||||
CallbackListPtr ClientStateCallback;
|
||||
OsTimerPtr dispatchExceptionTimer;
|
||||
|
||||
/* dispatchException & isItTimeToYield must be declared volatile since they
|
||||
* are modified by signal handlers - otherwise optimizer may assume it doesn't
|
||||
|
@ -399,6 +401,58 @@ SmartScheduleClient(void)
|
|||
return best;
|
||||
}
|
||||
|
||||
static CARD32
|
||||
DispatchExceptionCallback(OsTimerPtr timer, CARD32 time, void *arg)
|
||||
{
|
||||
dispatchException |= dispatchExceptionAtReset;
|
||||
|
||||
/* Don't re-arm the timer */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
CancelDispatchExceptionTimer(void)
|
||||
{
|
||||
TimerFree(dispatchExceptionTimer);
|
||||
dispatchExceptionTimer = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
SetDispatchExceptionTimer(void)
|
||||
{
|
||||
/* The timer delay is only for terminate, not reset */
|
||||
if (!(dispatchExceptionAtReset & DE_TERMINATE)) {
|
||||
dispatchException |= dispatchExceptionAtReset;
|
||||
return;
|
||||
}
|
||||
|
||||
CancelDispatchExceptionTimer();
|
||||
|
||||
if (terminateDelay == 0)
|
||||
dispatchException |= dispatchExceptionAtReset;
|
||||
else
|
||||
dispatchExceptionTimer = TimerSet(dispatchExceptionTimer,
|
||||
0, terminateDelay * 1000 /* msec */,
|
||||
&DispatchExceptionCallback,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static Bool
|
||||
ShouldDisconnectRemainingClients(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < currentMaxClients; i++) {
|
||||
if (clients[i]) {
|
||||
if (!XFixesShouldDisconnectClient(clients[i]))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* All remaining clients can be safely ignored */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
EnableLimitedSchedulingLatency(void)
|
||||
{
|
||||
|
@ -3419,6 +3473,7 @@ ProcNoOperation(ClientPtr client)
|
|||
*********************/
|
||||
|
||||
char dispatchExceptionAtReset = DE_RESET;
|
||||
int terminateDelay = 0;
|
||||
|
||||
void
|
||||
CloseDownClient(ClientPtr client)
|
||||
|
@ -3475,7 +3530,7 @@ CloseDownClient(ClientPtr client)
|
|||
|
||||
if (really_close_down) {
|
||||
if (client->clientState == ClientStateRunning && nClients == 0)
|
||||
dispatchException |= dispatchExceptionAtReset;
|
||||
SetDispatchExceptionTimer();
|
||||
|
||||
client->clientState = ClientStateGone;
|
||||
if (ClientStateCallback) {
|
||||
|
@ -3487,6 +3542,7 @@ CloseDownClient(ClientPtr client)
|
|||
CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
|
||||
}
|
||||
TouchListenerGone(client->clientAsMask);
|
||||
GestureListenerGone(client->clientAsMask);
|
||||
FreeClientResources(client);
|
||||
/* Disable client ID tracking. This must be done after
|
||||
* ClientStateCallback. */
|
||||
|
@ -3503,6 +3559,9 @@ CloseDownClient(ClientPtr client)
|
|||
while (!clients[currentMaxClients - 1])
|
||||
currentMaxClients--;
|
||||
}
|
||||
|
||||
if (ShouldDisconnectRemainingClients())
|
||||
SetDispatchExceptionTimer();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -3704,6 +3763,7 @@ SendConnSetup(ClientPtr client, const char *reason)
|
|||
clientinfo.setup = (xConnSetup *) lConnectionInfo;
|
||||
CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
|
||||
}
|
||||
CancelDispatchExceptionTimer();
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
*
|
||||
* For a full description of the focus in/out model from a window's
|
||||
* perspective, see
|
||||
* http://lists.freedesktop.org/archives/xorg/2008-December/041740.html
|
||||
* https://lists.freedesktop.org/archives/xorg/2008-December/041684.html
|
||||
*
|
||||
* Additional notes:
|
||||
* - The core protocol spec says that "In a LeaveNotify event, if a child of the
|
||||
|
|
|
@ -59,6 +59,8 @@ static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi);
|
|||
static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi);
|
||||
static int eventToBarrierEvent(BarrierEvent *ev, xEvent **xi);
|
||||
static int eventToTouchOwnershipEvent(TouchOwnershipEvent *ev, xEvent **xi);
|
||||
static int eventToGestureSwipeEvent(GestureEvent *ev, xEvent **xi);
|
||||
static int eventToGesturePinchEvent(GestureEvent *ev, xEvent **xi);
|
||||
|
||||
/* Do not use, read comments below */
|
||||
BOOL EventIsKeyRepeat(xEvent *event);
|
||||
|
@ -163,6 +165,12 @@ EventToCore(InternalEvent *event, xEvent **core_out, int *count_out)
|
|||
case ET_TouchOwnership:
|
||||
case ET_BarrierHit:
|
||||
case ET_BarrierLeave:
|
||||
case ET_GesturePinchBegin:
|
||||
case ET_GesturePinchUpdate:
|
||||
case ET_GesturePinchEnd:
|
||||
case ET_GestureSwipeBegin:
|
||||
case ET_GestureSwipeUpdate:
|
||||
case ET_GestureSwipeEnd:
|
||||
ret = BadMatch;
|
||||
break;
|
||||
default:
|
||||
|
@ -221,6 +229,12 @@ EventToXI(InternalEvent *ev, xEvent **xi, int *count)
|
|||
case ET_TouchOwnership:
|
||||
case ET_BarrierHit:
|
||||
case ET_BarrierLeave:
|
||||
case ET_GesturePinchBegin:
|
||||
case ET_GesturePinchUpdate:
|
||||
case ET_GesturePinchEnd:
|
||||
case ET_GestureSwipeBegin:
|
||||
case ET_GestureSwipeUpdate:
|
||||
case ET_GestureSwipeEnd:
|
||||
*count = 0;
|
||||
*xi = NULL;
|
||||
return BadMatch;
|
||||
|
@ -285,6 +299,14 @@ EventToXI2(InternalEvent *ev, xEvent **xi)
|
|||
case ET_BarrierHit:
|
||||
case ET_BarrierLeave:
|
||||
return eventToBarrierEvent(&ev->barrier_event, xi);
|
||||
case ET_GesturePinchBegin:
|
||||
case ET_GesturePinchUpdate:
|
||||
case ET_GesturePinchEnd:
|
||||
return eventToGesturePinchEvent(&ev->gesture_event, xi);
|
||||
case ET_GestureSwipeBegin:
|
||||
case ET_GestureSwipeUpdate:
|
||||
case ET_GestureSwipeEnd:
|
||||
return eventToGestureSwipeEvent(&ev->gesture_event, xi);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -816,6 +838,88 @@ eventToBarrierEvent(BarrierEvent *ev, xEvent **xi)
|
|||
return Success;
|
||||
}
|
||||
|
||||
int
|
||||
eventToGesturePinchEvent(GestureEvent *ev, xEvent **xi)
|
||||
{
|
||||
int len = sizeof(xXIGesturePinchEvent);
|
||||
xXIGesturePinchEvent *xpe;
|
||||
|
||||
*xi = calloc(1, len);
|
||||
xpe = (xXIGesturePinchEvent *) * xi;
|
||||
xpe->type = GenericEvent;
|
||||
xpe->extension = IReqCode;
|
||||
xpe->evtype = GetXI2Type(ev->type);
|
||||
xpe->time = ev->time;
|
||||
xpe->length = bytes_to_int32(len - sizeof(xEvent));
|
||||
xpe->detail = ev->num_touches;
|
||||
|
||||
xpe->root = ev->root;
|
||||
xpe->deviceid = ev->deviceid;
|
||||
xpe->sourceid = ev->sourceid;
|
||||
xpe->root_x = double_to_fp1616(ev->root_x);
|
||||
xpe->root_y = double_to_fp1616(ev->root_y);
|
||||
xpe->flags |= (ev->flags & GESTURE_CANCELLED) ? XIGesturePinchEventCancelled : 0;
|
||||
|
||||
xpe->delta_x = double_to_fp1616(ev->delta_x);
|
||||
xpe->delta_y = double_to_fp1616(ev->delta_y);
|
||||
xpe->delta_unaccel_x = double_to_fp1616(ev->delta_unaccel_x);
|
||||
xpe->delta_unaccel_y = double_to_fp1616(ev->delta_unaccel_y);
|
||||
xpe->scale = double_to_fp1616(ev->scale);
|
||||
xpe->delta_angle = double_to_fp1616(ev->delta_angle);
|
||||
|
||||
xpe->mods.base_mods = ev->mods.base;
|
||||
xpe->mods.latched_mods = ev->mods.latched;
|
||||
xpe->mods.locked_mods = ev->mods.locked;
|
||||
xpe->mods.effective_mods = ev->mods.effective;
|
||||
|
||||
xpe->group.base_group = ev->group.base;
|
||||
xpe->group.latched_group = ev->group.latched;
|
||||
xpe->group.locked_group = ev->group.locked;
|
||||
xpe->group.effective_group = ev->group.effective;
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
int
|
||||
eventToGestureSwipeEvent(GestureEvent *ev, xEvent **xi)
|
||||
{
|
||||
int len = sizeof(xXIGestureSwipeEvent);
|
||||
xXIGestureSwipeEvent *xde;
|
||||
|
||||
*xi = calloc(1, len);
|
||||
xde = (xXIGestureSwipeEvent *) * xi;
|
||||
xde->type = GenericEvent;
|
||||
xde->extension = IReqCode;
|
||||
xde->evtype = GetXI2Type(ev->type);
|
||||
xde->time = ev->time;
|
||||
xde->length = bytes_to_int32(len - sizeof(xEvent));
|
||||
xde->detail = ev->num_touches;
|
||||
|
||||
xde->root = ev->root;
|
||||
xde->deviceid = ev->deviceid;
|
||||
xde->sourceid = ev->sourceid;
|
||||
xde->root_x = double_to_fp1616(ev->root_x);
|
||||
xde->root_y = double_to_fp1616(ev->root_y);
|
||||
xde->flags |= (ev->flags & GESTURE_CANCELLED) ? XIGestureSwipeEventCancelled : 0;
|
||||
|
||||
xde->delta_x = double_to_fp1616(ev->delta_x);
|
||||
xde->delta_y = double_to_fp1616(ev->delta_y);
|
||||
xde->delta_unaccel_x = double_to_fp1616(ev->delta_unaccel_x);
|
||||
xde->delta_unaccel_y = double_to_fp1616(ev->delta_unaccel_y);
|
||||
|
||||
xde->mods.base_mods = ev->mods.base;
|
||||
xde->mods.latched_mods = ev->mods.latched;
|
||||
xde->mods.locked_mods = ev->mods.locked;
|
||||
xde->mods.effective_mods = ev->mods.effective;
|
||||
|
||||
xde->group.base_group = ev->group.base;
|
||||
xde->group.latched_group = ev->group.latched;
|
||||
xde->group.locked_group = ev->group.locked;
|
||||
xde->group.effective_group = ev->group.effective;
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the corresponding core type for the given event or 0 if no core
|
||||
* equivalent exists.
|
||||
|
@ -969,8 +1073,68 @@ GetXI2Type(enum EventType type)
|
|||
case ET_BarrierLeave:
|
||||
xi2type = XI_BarrierLeave;
|
||||
break;
|
||||
case ET_GesturePinchBegin:
|
||||
xi2type = XI_GesturePinchBegin;
|
||||
break;
|
||||
case ET_GesturePinchUpdate:
|
||||
xi2type = XI_GesturePinchUpdate;
|
||||
break;
|
||||
case ET_GesturePinchEnd:
|
||||
xi2type = XI_GesturePinchEnd;
|
||||
break;
|
||||
case ET_GestureSwipeBegin:
|
||||
xi2type = XI_GestureSwipeBegin;
|
||||
break;
|
||||
case ET_GestureSwipeUpdate:
|
||||
xi2type = XI_GestureSwipeUpdate;
|
||||
break;
|
||||
case ET_GestureSwipeEnd:
|
||||
xi2type = XI_GestureSwipeEnd;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return xi2type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a gesture type to corresponding Gesture{Pinch,Swipe}Begin.
|
||||
* Returns 0 if the input type is not a gesture.
|
||||
*/
|
||||
enum EventType
|
||||
GestureTypeToBegin(enum EventType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ET_GesturePinchBegin:
|
||||
case ET_GesturePinchUpdate:
|
||||
case ET_GesturePinchEnd:
|
||||
return ET_GesturePinchBegin;
|
||||
case ET_GestureSwipeBegin:
|
||||
case ET_GestureSwipeUpdate:
|
||||
case ET_GestureSwipeEnd:
|
||||
return ET_GestureSwipeBegin;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a gesture type to corresponding Gesture{Pinch,Swipe}End.
|
||||
* Returns 0 if the input type is not a gesture.
|
||||
*/
|
||||
enum EventType
|
||||
GestureTypeToEnd(enum EventType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ET_GesturePinchBegin:
|
||||
case ET_GesturePinchUpdate:
|
||||
case ET_GesturePinchEnd:
|
||||
return ET_GesturePinchEnd;
|
||||
case ET_GestureSwipeBegin:
|
||||
case ET_GestureSwipeUpdate:
|
||||
case ET_GestureSwipeEnd:
|
||||
return ET_GestureSwipeEnd;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
134
dix/events.c
134
dix/events.c
|
@ -1328,6 +1328,15 @@ ComputeFreezes(void)
|
|||
|
||||
TouchListenerAcceptReject(replayDev, ti, 0, XIRejectTouch);
|
||||
}
|
||||
else if (IsGestureEvent(event)) {
|
||||
GestureInfoPtr gi =
|
||||
GestureFindActiveByEventType(replayDev, event->any.type);
|
||||
if (gi) {
|
||||
GestureEmitGestureEndToOwner(replayDev, gi);
|
||||
GestureEndGesture(gi);
|
||||
}
|
||||
ProcessGestureEvent(event, replayDev);
|
||||
}
|
||||
else {
|
||||
WindowPtr w = XYToWindow(replayDev->spriteInfo->sprite,
|
||||
event->device_event.root_x,
|
||||
|
@ -1480,16 +1489,28 @@ UpdateTouchesForGrab(DeviceIntPtr mouse)
|
|||
|
||||
if (ti->active &&
|
||||
CLIENT_BITS(listener->listener) == grab->resource) {
|
||||
if (grab->grabtype == CORE || grab->grabtype == XI ||
|
||||
!xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin)) {
|
||||
|
||||
if (listener->type == TOUCH_LISTENER_REGULAR &&
|
||||
listener->state != TOUCH_LISTENER_AWAITING_BEGIN &&
|
||||
listener->state != TOUCH_LISTENER_HAS_END) {
|
||||
/* if the listener already got any events relating to the touch, we must send
|
||||
a touch end because the grab overrides the previous listener and won't
|
||||
itself send any touch events.
|
||||
*/
|
||||
TouchEmitTouchEnd(mouse, ti, 0, listener->listener);
|
||||
}
|
||||
listener->type = TOUCH_LISTENER_POINTER_GRAB;
|
||||
} else {
|
||||
listener->type = TOUCH_LISTENER_GRAB;
|
||||
}
|
||||
|
||||
listener->listener = grab->resource;
|
||||
listener->level = grab->grabtype;
|
||||
listener->state = TOUCH_LISTENER_IS_OWNER;
|
||||
listener->window = grab->window;
|
||||
listener->state = TOUCH_LISTENER_IS_OWNER;
|
||||
|
||||
if (grab->grabtype == CORE || grab->grabtype == XI ||
|
||||
!xi2mask_isset(grab->xi2mask, mouse, XI_TouchBegin))
|
||||
listener->type = TOUCH_LISTENER_POINTER_GRAB;
|
||||
else
|
||||
listener->type = TOUCH_LISTENER_GRAB;
|
||||
if (listener->grab)
|
||||
FreeGrab(listener->grab);
|
||||
listener->grab = AllocGrab(grab);
|
||||
|
@ -1497,6 +1518,46 @@ UpdateTouchesForGrab(DeviceIntPtr mouse)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update gesture records when an explicit grab is activated. Any gestures owned
|
||||
* by the grabbing client are updated so the listener state reflects the new
|
||||
* grab.
|
||||
*/
|
||||
static void
|
||||
UpdateGesturesForGrab(DeviceIntPtr mouse)
|
||||
{
|
||||
if (!mouse->gesture || mouse->deviceGrab.fromPassiveGrab)
|
||||
return;
|
||||
|
||||
GestureInfoPtr gi = &mouse->gesture->gesture;
|
||||
GestureListener *listener = &gi->listener;
|
||||
GrabPtr grab = mouse->deviceGrab.grab;
|
||||
|
||||
if (gi->active && CLIENT_BITS(listener->listener) == grab->resource) {
|
||||
if (grab->grabtype == CORE || grab->grabtype == XI ||
|
||||
!xi2mask_isset(grab->xi2mask, mouse, GetXI2Type(gi->type))) {
|
||||
|
||||
if (listener->type == GESTURE_LISTENER_REGULAR) {
|
||||
/* if the listener already got any events relating to the gesture, we must send
|
||||
a gesture end because the grab overrides the previous listener and won't
|
||||
itself send any gesture events.
|
||||
*/
|
||||
GestureEmitGestureEndToOwner(mouse, gi);
|
||||
}
|
||||
listener->type = GESTURE_LISTENER_NONGESTURE_GRAB;
|
||||
} else {
|
||||
listener->type = GESTURE_LISTENER_GRAB;
|
||||
}
|
||||
|
||||
listener->listener = grab->resource;
|
||||
listener->window = grab->window;
|
||||
|
||||
if (listener->grab)
|
||||
FreeGrab(listener->grab);
|
||||
listener->grab = AllocGrab(grab);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate a pointer grab on the given device. A pointer grab will cause all
|
||||
* core pointer events of this device to be delivered to the grabbing client only.
|
||||
|
@ -1547,6 +1608,7 @@ ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab,
|
|||
grabinfo->implicitGrab = autoGrab & ImplicitGrabMask;
|
||||
PostNewCursor(mouse);
|
||||
UpdateTouchesForGrab(mouse);
|
||||
UpdateGesturesForGrab(mouse);
|
||||
CheckGrabForSyncs(mouse, (Bool) grab->pointerMode,
|
||||
(Bool) grab->keyboardMode);
|
||||
if (oldgrab)
|
||||
|
@ -1602,6 +1664,16 @@ DeactivatePointerGrab(DeviceIntPtr mouse)
|
|||
if (dev->deviceGrab.sync.other == grab)
|
||||
dev->deviceGrab.sync.other = NullGrab;
|
||||
}
|
||||
|
||||
/* in case of explicit gesture grab, send end event to the grab client */
|
||||
if (!wasPassive && mouse->gesture) {
|
||||
GestureInfoPtr gi = &mouse->gesture->gesture;
|
||||
if (gi->active && GestureResourceIsOwner(gi, grab_resource)) {
|
||||
GestureEmitGestureEndToOwner(mouse, gi);
|
||||
GestureEndGesture(gi);
|
||||
}
|
||||
}
|
||||
|
||||
DoEnterLeaveEvents(mouse, mouse->id, grab->window,
|
||||
mouse->spriteInfo->sprite->win, NotifyUngrab);
|
||||
if (grab->confineTo)
|
||||
|
@ -2533,6 +2605,44 @@ FixUpXI2DeviceEventFromWindow(SpritePtr pSprite, int evtype,
|
|||
(pSprite->hot.pScreen == pWin->drawable.pScreen);
|
||||
}
|
||||
|
||||
static void
|
||||
FixUpXI2PinchEventFromWindow(SpritePtr pSprite, xXIGesturePinchEvent *event,
|
||||
WindowPtr pWin, Window child)
|
||||
{
|
||||
event->root = RootWindow(pSprite)->drawable.id;
|
||||
event->event = pWin->drawable.id;
|
||||
|
||||
if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
|
||||
event->event_x = event->root_x - double_to_fp1616(pWin->drawable.x);
|
||||
event->event_y = event->root_y - double_to_fp1616(pWin->drawable.y);
|
||||
event->child = child;
|
||||
}
|
||||
else {
|
||||
event->event_x = 0;
|
||||
event->event_y = 0;
|
||||
event->child = None;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
FixUpXI2SwipeEventFromWindow(SpritePtr pSprite, xXIGestureSwipeEvent *event,
|
||||
WindowPtr pWin, Window child)
|
||||
{
|
||||
event->root = RootWindow(pSprite)->drawable.id;
|
||||
event->event = pWin->drawable.id;
|
||||
|
||||
if (pSprite->hot.pScreen == pWin->drawable.pScreen) {
|
||||
event->event_x = event->root_x - double_to_fp1616(pWin->drawable.x);
|
||||
event->event_y = event->root_y - double_to_fp1616(pWin->drawable.y);
|
||||
event->child = child;
|
||||
}
|
||||
else {
|
||||
event->event_x = 0;
|
||||
event->event_y = 0;
|
||||
event->child = None;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust event fields to comply with the window properties.
|
||||
*
|
||||
|
@ -2566,6 +2676,18 @@ FixUpEventFromWindow(SpritePtr pSprite,
|
|||
case XI_BarrierHit:
|
||||
case XI_BarrierLeave:
|
||||
return;
|
||||
case XI_GesturePinchBegin:
|
||||
case XI_GesturePinchUpdate:
|
||||
case XI_GesturePinchEnd:
|
||||
FixUpXI2PinchEventFromWindow(pSprite,
|
||||
(xXIGesturePinchEvent*) xE, pWin, child);
|
||||
break;
|
||||
case XI_GestureSwipeBegin:
|
||||
case XI_GestureSwipeUpdate:
|
||||
case XI_GestureSwipeEnd:
|
||||
FixUpXI2SwipeEventFromWindow(pSprite,
|
||||
(xXIGestureSwipeEvent*) xE, pWin, child);
|
||||
break;
|
||||
default:
|
||||
FixUpXI2DeviceEventFromWindow(pSprite, evtype,
|
||||
(xXIDeviceEvent*) xE, pWin, child);
|
||||
|
|
|
@ -0,0 +1,362 @@
|
|||
/*
|
||||
* Copyright © 2011 Collabra Ltd.
|
||||
* Copyright © 2011 Red Hat, Inc.
|
||||
* Copyright © 2020 Povilas Kanapickas <povilas@radix.lt>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include "inputstr.h"
|
||||
#include "scrnintstr.h"
|
||||
#include "dixgrabs.h"
|
||||
|
||||
#include "eventstr.h"
|
||||
#include "exevents.h"
|
||||
#include "exglobals.h"
|
||||
#include "inpututils.h"
|
||||
#include "eventconvert.h"
|
||||
#include "windowstr.h"
|
||||
#include "mi.h"
|
||||
|
||||
#define GESTURE_HISTORY_SIZE 100
|
||||
|
||||
Bool
|
||||
GestureInitGestureInfo(GestureInfoPtr gi)
|
||||
{
|
||||
memset(gi, 0, sizeof(*gi));
|
||||
|
||||
gi->sprite.spriteTrace = calloc(32, sizeof(*gi->sprite.spriteTrace));
|
||||
if (!gi->sprite.spriteTrace) {
|
||||
return FALSE;
|
||||
}
|
||||
gi->sprite.spriteTraceSize = 32;
|
||||
gi->sprite.spriteTrace[0] = screenInfo.screens[0]->root;
|
||||
gi->sprite.hot.pScreen = screenInfo.screens[0];
|
||||
gi->sprite.hotPhys.pScreen = screenInfo.screens[0];
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an event type returns the associated gesture event info.
|
||||
*/
|
||||
GestureInfoPtr
|
||||
GestureFindActiveByEventType(DeviceIntPtr dev, int type)
|
||||
{
|
||||
GestureClassPtr g = dev->gesture;
|
||||
enum EventType type_to_expect = GestureTypeToBegin(type);
|
||||
|
||||
if (!g || type_to_expect == 0 || !g->gesture.active ||
|
||||
g->gesture.type != type_to_expect) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &g->gesture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up gesture info for a new gesture. Returns NULL on failure.
|
||||
*/
|
||||
GestureInfoPtr
|
||||
GestureBeginGesture(DeviceIntPtr dev, InternalEvent *ev)
|
||||
{
|
||||
GestureClassPtr g = dev->gesture;
|
||||
enum EventType gesture_type = GestureTypeToBegin(ev->any.type);
|
||||
|
||||
/* Note that we ignore begin events when an existing gesture is active */
|
||||
if (!g || gesture_type == 0 || g->gesture.active)
|
||||
return NULL;
|
||||
|
||||
g->gesture.type = gesture_type;
|
||||
|
||||
if (!GestureBuildSprite(dev, &g->gesture))
|
||||
return NULL;
|
||||
|
||||
g->gesture.active = TRUE;
|
||||
g->gesture.num_touches = ev->gesture_event.num_touches;
|
||||
g->gesture.sourceid = ev->gesture_event.sourceid;
|
||||
g->gesture.has_listener = FALSE;
|
||||
return &g->gesture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a gesture: this must only be called after all events
|
||||
* related to that gesture have been sent and finalised.
|
||||
*/
|
||||
void
|
||||
GestureEndGesture(GestureInfoPtr gi)
|
||||
{
|
||||
if (gi->has_listener) {
|
||||
if (gi->listener.grab) {
|
||||
FreeGrab(gi->listener.grab);
|
||||
gi->listener.grab = NULL;
|
||||
}
|
||||
gi->listener.listener = 0;
|
||||
gi->has_listener = FALSE;
|
||||
}
|
||||
|
||||
gi->active = FALSE;
|
||||
gi->num_touches = 0;
|
||||
gi->sprite.spriteTraceGood = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure a window trace is present in gi->sprite, constructing one for
|
||||
* Gesture{Pinch,Swipe}Begin events.
|
||||
*/
|
||||
Bool
|
||||
GestureBuildSprite(DeviceIntPtr sourcedev, GestureInfoPtr gi)
|
||||
{
|
||||
SpritePtr sprite = &gi->sprite;
|
||||
|
||||
if (!sourcedev->spriteInfo->sprite)
|
||||
return FALSE;
|
||||
|
||||
if (!CopySprite(sourcedev->spriteInfo->sprite, sprite))
|
||||
return FALSE;
|
||||
|
||||
if (sprite->spriteTraceGood <= 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns TRUE if the specified grab or selection is the current owner of
|
||||
* the gesture sequence.
|
||||
*/
|
||||
Bool
|
||||
GestureResourceIsOwner(GestureInfoPtr gi, XID resource)
|
||||
{
|
||||
return (gi->listener.listener == resource);
|
||||
}
|
||||
|
||||
void
|
||||
GestureAddListener(GestureInfoPtr gi, XID resource, int resource_type,
|
||||
enum GestureListenerType type, WindowPtr window, const GrabPtr grab)
|
||||
{
|
||||
GrabPtr g = NULL;
|
||||
|
||||
BUG_RETURN(gi->has_listener);
|
||||
|
||||
/* We need a copy of the grab, not the grab itself since that may be deleted by
|
||||
* a UngrabButton request and leaves us with a dangling pointer */
|
||||
if (grab)
|
||||
g = AllocGrab(grab);
|
||||
|
||||
gi->listener.listener = resource;
|
||||
gi->listener.resource_type = resource_type;
|
||||
gi->listener.type = type;
|
||||
gi->listener.window = window;
|
||||
gi->listener.grab = g;
|
||||
gi->has_listener = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
GestureAddGrabListener(DeviceIntPtr dev, GestureInfoPtr gi, GrabPtr grab)
|
||||
{
|
||||
enum GestureListenerType type;
|
||||
|
||||
/* FIXME: owner_events */
|
||||
|
||||
if (grab->grabtype == XI2) {
|
||||
if (xi2mask_isset(grab->xi2mask, dev, XI_GesturePinchBegin) ||
|
||||
xi2mask_isset(grab->xi2mask, dev, XI_GestureSwipeBegin)) {
|
||||
type = GESTURE_LISTENER_GRAB;
|
||||
} else
|
||||
type = GESTURE_LISTENER_NONGESTURE_GRAB;
|
||||
}
|
||||
else if (grab->grabtype == XI || grab->grabtype == CORE) {
|
||||
type = GESTURE_LISTENER_NONGESTURE_GRAB;
|
||||
}
|
||||
else {
|
||||
BUG_RETURN_MSG(1, "Unsupported grab type\n");
|
||||
}
|
||||
|
||||
/* grab listeners are always RT_NONE since we keep the grab pointer */
|
||||
GestureAddListener(gi, grab->resource, RT_NONE, type, grab->window, grab);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one listener if there is a grab on the given window.
|
||||
*/
|
||||
static void
|
||||
GestureAddPassiveGrabListener(DeviceIntPtr dev, GestureInfoPtr gi, WindowPtr win, InternalEvent *ev)
|
||||
{
|
||||
Bool activate = FALSE;
|
||||
Bool check_core = FALSE;
|
||||
|
||||
GrabPtr grab = CheckPassiveGrabsOnWindow(win, dev, ev, check_core,
|
||||
activate);
|
||||
if (!grab)
|
||||
return;
|
||||
|
||||
/* We'll deliver later in gesture-specific code */
|
||||
ActivateGrabNoDelivery(dev, grab, ev, ev);
|
||||
GestureAddGrabListener(dev, gi, grab);
|
||||
}
|
||||
|
||||
static void
|
||||
GestureAddRegularListener(DeviceIntPtr dev, GestureInfoPtr gi, WindowPtr win, InternalEvent *ev)
|
||||
{
|
||||
InputClients *iclients = NULL;
|
||||
OtherInputMasks *inputMasks = NULL;
|
||||
uint16_t evtype = GetXI2Type(ev->any.type);
|
||||
int mask;
|
||||
|
||||
mask = EventIsDeliverable(dev, ev->any.type, win);
|
||||
if (!mask)
|
||||
return;
|
||||
|
||||
inputMasks = wOtherInputMasks(win);
|
||||
|
||||
if (mask & EVENT_XI2_MASK) {
|
||||
nt_list_for_each_entry(iclients, inputMasks->inputClients, next) {
|
||||
if (!xi2mask_isset(iclients->xi2mask, dev, evtype))
|
||||
continue;
|
||||
|
||||
GestureAddListener(gi, iclients->resource, RT_INPUTCLIENT,
|
||||
GESTURE_LISTENER_REGULAR, win, NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GestureSetupListener(DeviceIntPtr dev, GestureInfoPtr gi, InternalEvent *ev)
|
||||
{
|
||||
int i;
|
||||
SpritePtr sprite = &gi->sprite;
|
||||
WindowPtr win;
|
||||
|
||||
/* Any current grab will consume all gesture events */
|
||||
if (dev->deviceGrab.grab) {
|
||||
GestureAddGrabListener(dev, gi, dev->deviceGrab.grab);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find passive grab that would be activated by this event, if any. If we're handling
|
||||
* ReplayDevice then the search starts from the descendant of the grab window, otherwise
|
||||
* the search starts at the root window. The search ends at deepest child window. */
|
||||
i = 0;
|
||||
if (syncEvents.playingEvents) {
|
||||
while (i < dev->spriteInfo->sprite->spriteTraceGood) {
|
||||
if (dev->spriteInfo->sprite->spriteTrace[i++] == syncEvents.replayWin)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < sprite->spriteTraceGood; i++) {
|
||||
win = sprite->spriteTrace[i];
|
||||
GestureAddPassiveGrabListener(dev, gi, win, ev);
|
||||
if (gi->has_listener)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find the first client with an applicable event selection,
|
||||
* going from deepest child window back up to the root window. */
|
||||
for (i = sprite->spriteTraceGood - 1; i >= 0; i--) {
|
||||
win = sprite->spriteTrace[i];
|
||||
GestureAddRegularListener(dev, gi, win, ev);
|
||||
if (gi->has_listener)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* As gesture grabs don't turn into active grabs with their own resources, we
|
||||
* need to walk all the gestures and remove this grab from listener */
|
||||
void
|
||||
GestureListenerGone(XID resource)
|
||||
{
|
||||
GestureInfoPtr gi;
|
||||
DeviceIntPtr dev;
|
||||
InternalEvent *events = InitEventList(GetMaximumEventsNum());
|
||||
|
||||
if (!events)
|
||||
FatalError("GestureListenerGone: couldn't allocate events\n");
|
||||
|
||||
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||||
if (!dev->gesture)
|
||||
continue;
|
||||
|
||||
gi = &dev->gesture->gesture;
|
||||
if (!gi->active)
|
||||
continue;
|
||||
|
||||
if (CLIENT_BITS(gi->listener.listener) == resource)
|
||||
GestureEndGesture(gi);
|
||||
}
|
||||
|
||||
FreeEventList(events, GetMaximumEventsNum());
|
||||
}
|
||||
|
||||
/**
|
||||
* End physically active gestures for a device.
|
||||
*/
|
||||
void
|
||||
GestureEndActiveGestures(DeviceIntPtr dev)
|
||||
{
|
||||
GestureClassPtr g = dev->gesture;
|
||||
InternalEvent *eventlist;
|
||||
|
||||
if (!g)
|
||||
return;
|
||||
|
||||
eventlist = InitEventList(GetMaximumEventsNum());
|
||||
|
||||
input_lock();
|
||||
mieqProcessInputEvents();
|
||||
if (g->gesture.active) {
|
||||
int j;
|
||||
int type = GetXI2Type(GestureTypeToEnd(g->gesture.type));
|
||||
int nevents = GetGestureEvents(eventlist, dev, type, g->gesture.num_touches,
|
||||
0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
for (j = 0; j < nevents; j++)
|
||||
mieqProcessDeviceEvent(dev, eventlist + j, NULL);
|
||||
}
|
||||
input_unlock();
|
||||
|
||||
FreeEventList(eventlist, GetMaximumEventsNum());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and deliver a Gesture{Pinch,Swipe}End event to the owner.
|
||||
*
|
||||
* @param dev The device to deliver the event for.
|
||||
* @param gi The gesture record to deliver the event for.
|
||||
*/
|
||||
void
|
||||
GestureEmitGestureEndToOwner(DeviceIntPtr dev, GestureInfoPtr gi)
|
||||
{
|
||||
InternalEvent event;
|
||||
/* We're not processing a gesture end for a frozen device */
|
||||
if (dev->deviceGrab.sync.frozen)
|
||||
return;
|
||||
|
||||
DeliverDeviceClassesChangedEvent(gi->sourceid, GetTimeInMillis());
|
||||
InitGestureEvent(&event, dev, GetTimeInMillis(), GestureTypeToEnd(gi->type),
|
||||
0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||
DeliverGestureEventToOwner(dev, gi, &event);
|
||||
}
|
136
dix/getevents.c
136
dix/getevents.c
|
@ -2099,3 +2099,139 @@ PostSyntheticMotion(DeviceIntPtr pDev,
|
|||
/* FIXME: MD/SD considerations? */
|
||||
(*pDev->public.processInputProc) ((InternalEvent *) &ev, pDev);
|
||||
}
|
||||
|
||||
void
|
||||
InitGestureEvent(InternalEvent *ievent, DeviceIntPtr dev, CARD32 ms,
|
||||
int type, uint16_t num_touches, uint32_t flags,
|
||||
double delta_x, double delta_y,
|
||||
double delta_unaccel_x, double delta_unaccel_y,
|
||||
double scale, double delta_angle)
|
||||
{
|
||||
ScreenPtr scr = dev->spriteInfo->sprite->hotPhys.pScreen;
|
||||
GestureEvent *event = &ievent->gesture_event;
|
||||
double screenx = 0.0, screeny = 0.0; /* desktop coordinate system */
|
||||
|
||||
init_gesture_event(event, dev, ms);
|
||||
|
||||
screenx = dev->spriteInfo->sprite->hotPhys.x;
|
||||
screeny = dev->spriteInfo->sprite->hotPhys.y;
|
||||
|
||||
event->type = type;
|
||||
event->root = scr->root->drawable.id;
|
||||
event->root_x = screenx - scr->x;
|
||||
event->root_y = screeny - scr->y;
|
||||
event->num_touches = num_touches;
|
||||
event->flags = flags;
|
||||
|
||||
event->delta_x = delta_x;
|
||||
event->delta_y = delta_y;
|
||||
event->delta_unaccel_x = delta_unaccel_x;
|
||||
event->delta_unaccel_y = delta_unaccel_y;
|
||||
event->scale = scale;
|
||||
event->delta_angle = delta_angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get events for a pinch or swipe gesture.
|
||||
*
|
||||
* events is not NULL-terminated; the return value is the number of events.
|
||||
* The DDX is responsible for allocating the event structure in the first
|
||||
* place via GetMaximumEventsNum(), and for freeing it.
|
||||
*
|
||||
* @param[out] events The list of events generated
|
||||
* @param dev The device to generate the events for
|
||||
* @param type XI_Gesture{Pinch,Swipe}{Begin,Update,End}
|
||||
* @prama num_touches The number of touches in the gesture
|
||||
* @param flags Event flags
|
||||
* @param delta_x,delta_y accelerated relative motion delta
|
||||
* @param delta_unaccel_x,delta_unaccel_y unaccelerated relative motion delta
|
||||
* @param scale (valid only to pinch events) absolute scale of a pinch gesture
|
||||
* @param delta_angle (valid only to pinch events) the ange delta in degrees between the last and
|
||||
* the current pinch event.
|
||||
*/
|
||||
int
|
||||
GetGestureEvents(InternalEvent *events, DeviceIntPtr dev,
|
||||
uint16_t type, uint16_t num_touches, uint32_t flags,
|
||||
double delta_x, double delta_y,
|
||||
double delta_unaccel_x, double delta_unaccel_y,
|
||||
double scale, double delta_angle)
|
||||
|
||||
{
|
||||
GestureClassPtr g = dev->gesture;
|
||||
CARD32 ms = GetTimeInMillis();
|
||||
enum EventType evtype;
|
||||
int num_events = 0;
|
||||
uint32_t evflags = 0;
|
||||
|
||||
if (!dev->enabled || !g)
|
||||
return 0;
|
||||
|
||||
if (!IsMaster(dev))
|
||||
events = UpdateFromMaster(events, dev, DEVCHANGE_POINTER_EVENT,
|
||||
&num_events);
|
||||
|
||||
switch (type) {
|
||||
case XI_GesturePinchBegin:
|
||||
evtype = ET_GesturePinchBegin;
|
||||
break;
|
||||
case XI_GesturePinchUpdate:
|
||||
evtype = ET_GesturePinchUpdate;
|
||||
break;
|
||||
case XI_GesturePinchEnd:
|
||||
evtype = ET_GesturePinchEnd;
|
||||
if (flags & XIGesturePinchEventCancelled)
|
||||
evflags |= GESTURE_CANCELLED;
|
||||
break;
|
||||
case XI_GestureSwipeBegin:
|
||||
evtype = ET_GestureSwipeBegin;
|
||||
break;
|
||||
case XI_GestureSwipeUpdate:
|
||||
evtype = ET_GestureSwipeUpdate;
|
||||
break;
|
||||
case XI_GestureSwipeEnd:
|
||||
evtype = ET_GestureSwipeEnd;
|
||||
if (flags & XIGestureSwipeEventCancelled)
|
||||
evflags |= GESTURE_CANCELLED;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
InitGestureEvent(events, dev, ms, evtype, num_touches, evflags,
|
||||
delta_x, delta_y, delta_unaccel_x, delta_unaccel_y,
|
||||
scale, delta_angle);
|
||||
num_events++;
|
||||
|
||||
return num_events;
|
||||
}
|
||||
|
||||
void
|
||||
QueueGesturePinchEvents(DeviceIntPtr dev, uint16_t type,
|
||||
uint16_t num_touches, uint32_t flags,
|
||||
double delta_x, double delta_y,
|
||||
double delta_unaccel_x,
|
||||
double delta_unaccel_y,
|
||||
double scale, double delta_angle)
|
||||
{
|
||||
int nevents;
|
||||
nevents = GetGestureEvents(InputEventList, dev, type, num_touches, flags,
|
||||
delta_x, delta_y,
|
||||
delta_unaccel_x, delta_unaccel_y,
|
||||
scale, delta_angle);
|
||||
queueEventList(dev, InputEventList, nevents);
|
||||
}
|
||||
|
||||
void
|
||||
QueueGestureSwipeEvents(DeviceIntPtr dev, uint16_t type,
|
||||
uint16_t num_touches, uint32_t flags,
|
||||
double delta_x, double delta_y,
|
||||
double delta_unaccel_x,
|
||||
double delta_unaccel_y)
|
||||
{
|
||||
int nevents;
|
||||
nevents = GetGestureEvents(InputEventList, dev, type, num_touches, flags,
|
||||
delta_x, delta_y,
|
||||
delta_unaccel_x, delta_unaccel_y,
|
||||
0.0, 0.0);
|
||||
queueEventList(dev, InputEventList, nevents);
|
||||
}
|
||||
|
|
|
@ -716,3 +716,10 @@ GrabIsKeyboardGrab(GrabPtr grab)
|
|||
return (grab->type == KeyPress ||
|
||||
grab->type == DeviceKeyPress || grab->type == XI_KeyPress);
|
||||
}
|
||||
|
||||
Bool
|
||||
GrabIsGestureGrab(GrabPtr grab)
|
||||
{
|
||||
return (grab->type == XI_GesturePinchBegin ||
|
||||
grab->type == XI_GestureSwipeBegin);
|
||||
}
|
||||
|
|
|
@ -746,6 +746,21 @@ init_device_event(DeviceEvent *event, DeviceIntPtr dev, Time ms,
|
|||
event->source_type = source_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the given gesture event to zero (or default values),
|
||||
* for the given device.
|
||||
*/
|
||||
void
|
||||
init_gesture_event(GestureEvent *event, DeviceIntPtr dev, Time ms)
|
||||
{
|
||||
memset(event, 0, sizeof(GestureEvent));
|
||||
event->header = ET_Internal;
|
||||
event->length = sizeof(GestureEvent);
|
||||
event->time = ms;
|
||||
event->deviceid = dev->id;
|
||||
event->sourceid = dev->id;
|
||||
}
|
||||
|
||||
int
|
||||
event_get_corestate(DeviceIntPtr mouse, DeviceIntPtr kbd)
|
||||
{
|
||||
|
@ -794,6 +809,24 @@ event_set_state(DeviceIntPtr mouse, DeviceIntPtr kbd, DeviceEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
event_set_state_gesture(DeviceIntPtr kbd, GestureEvent *event)
|
||||
{
|
||||
if (kbd && kbd->key) {
|
||||
XkbStatePtr state= &kbd->key->xkbInfo->state;
|
||||
|
||||
event->mods.base = state->base_mods;
|
||||
event->mods.latched = state->latched_mods;
|
||||
event->mods.locked = state->locked_mods;
|
||||
event->mods.effective = state->mods;
|
||||
|
||||
event->group.base = state->base_group;
|
||||
event->group.latched = state->latched_group;
|
||||
event->group.locked = state->locked_group;
|
||||
event->group.effective = state->group;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the event filter mask for the given device and the given core or
|
||||
* XI1 protocol type.
|
||||
|
|
|
@ -99,6 +99,7 @@ Equipment Corporation.
|
|||
#include <X11/fonts/libxfont2.h>
|
||||
#include "opaque.h"
|
||||
#include "servermd.h"
|
||||
#include "hotplug.h"
|
||||
#include "dixfont.h"
|
||||
#include "extnsionst.h"
|
||||
#include "privates.h"
|
||||
|
|
|
@ -12,6 +12,7 @@ srcs_dix = [
|
|||
'eventconvert.c',
|
||||
'extension.c',
|
||||
'gc.c',
|
||||
'gestures.c',
|
||||
'getevents.c',
|
||||
'globals.c',
|
||||
'glyphcurs.c',
|
||||
|
|
|
@ -253,7 +253,7 @@ ProcChangeProperty(ClientPtr client)
|
|||
int
|
||||
dixChangeWindowProperty(ClientPtr pClient, WindowPtr pWin, Atom property,
|
||||
Atom type, int format, int mode, unsigned long len,
|
||||
void *value, Bool sendevent)
|
||||
const void *value, Bool sendevent)
|
||||
{
|
||||
PropertyPtr pProp;
|
||||
PropertyRec savedProp;
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
SUBDIRS = dtrace
|
||||
|
||||
if ENABLE_DEVEL_DOCS
|
||||
if HAVE_XMLTO
|
||||
|
||||
# Main DocBook/XML files (DOCTYPE book)
|
||||
docbook = Xserver-spec.xml Xinput.xml
|
||||
|
||||
# Generate DocBook/XML output formats with or without stylesheets
|
||||
include $(top_srcdir)/devbook.am
|
||||
|
||||
endif HAVE_XMLTO
|
||||
endif ENABLE_DEVEL_DOCS
|
||||
|
||||
EXTRA_DIST = smartsched filter-xmlto.sh
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
if ENABLE_DOCS
|
||||
if XSERVER_DTRACE
|
||||
|
||||
# Main DocBook/XML files (DOCTYPE book)
|
||||
docbook = Xserver-DTrace.xml
|
||||
|
||||
# The location where the DocBook/XML files and their generated formats are installed
|
||||
shelfdir = $(docdir)
|
||||
|
||||
# Generate DocBook/XML output formats with or without stylesheets
|
||||
include $(top_srcdir)/docbook.am
|
||||
|
||||
endif XSERVER_DTRACE
|
||||
endif ENABLE_DOCS
|
|
@ -0,0 +1,64 @@
|
|||
|
||||
if build_docs
|
||||
basename = 'Xserver-DTrace'
|
||||
|
||||
input_xml = basename + '.xml'
|
||||
|
||||
custom_target(
|
||||
basename + '.html',
|
||||
output: basename + '.html',
|
||||
input: [input_xml],
|
||||
command: [xmlto] + docs_xmlto_search_flags + [
|
||||
'-x', join_paths(doc_stylesheet_srcdir, 'xorg-xhtml.xsl'),
|
||||
'--stringparam', 'target.database.document=' + join_paths(doc_sgml_path, 'X11/dbs/masterdb.html.xml'),
|
||||
'--stringparam', 'current.docid=' + basename,
|
||||
'-o', meson.current_build_dir(),
|
||||
'xhtml-nochunks', '@INPUT0@'],
|
||||
build_by_default: true,
|
||||
install: true,
|
||||
install_dir: join_paths(get_option('datadir'), 'doc/xorg-server'),
|
||||
)
|
||||
|
||||
if build_docs_pdf
|
||||
foreach format : ['ps', 'pdf']
|
||||
output_fn = basename + '.' + format
|
||||
custom_target(
|
||||
output_fn,
|
||||
output: output_fn,
|
||||
input: [input_xml],
|
||||
command: [xmlto] + docs_xmlto_search_flags + [
|
||||
'-x', join_paths(doc_stylesheet_srcdir, 'xorg-fo.xsl'),
|
||||
'--stringparam', 'img.src.path=' + meson.current_build_dir(),
|
||||
'--stringparam', 'target.database.document=' + join_paths(doc_sgml_path, 'X11/dbs/masterdb.pdf.xml'),
|
||||
'--stringparam', 'current.docid=' + basename,
|
||||
'-o', meson.current_build_dir(),
|
||||
'--with-fop', format, '@INPUT0@'],
|
||||
build_by_default: true,
|
||||
install: true,
|
||||
install_dir: join_paths(get_option('datadir'), 'doc/xorg-server'),
|
||||
)
|
||||
endforeach
|
||||
endif
|
||||
|
||||
foreach format_data : [['html', 'xorg-xhtml.xsl'], ['pdf', 'xorg-fo.xsl']]
|
||||
format = format_data[0]
|
||||
stylesheet = format_data[1]
|
||||
output_fn = basename + '.' + format + '.db'
|
||||
custom_target(
|
||||
output_fn,
|
||||
output: output_fn,
|
||||
input: [input_xml],
|
||||
command: [xsltproc] + docs_xslt_search_flags + [
|
||||
'--stringparam', 'targets.filename', output_fn,
|
||||
'--stringparam', 'collect.xref.targets', 'only',
|
||||
'--stringparam', 'olink.base.uri', basename + '.' + format,
|
||||
'--nonet',
|
||||
'--output', join_paths(meson.current_build_dir(), output_fn),
|
||||
'--xinclude', join_paths(doc_stylesheet_srcdir, stylesheet),
|
||||
'@INPUT0@'],
|
||||
build_by_default: true,
|
||||
install: true,
|
||||
install_dir: join_paths(get_option('datadir'), 'doc/xorg-server'),
|
||||
)
|
||||
endforeach
|
||||
endif
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
if build_docs_devel
|
||||
foreach basename : ['Xserver-spec', 'Xinput']
|
||||
|
||||
input_xml = basename + '.xml'
|
||||
|
||||
custom_target(
|
||||
basename + '.html',
|
||||
output: basename + '.html',
|
||||
input: [input_xml],
|
||||
command: [xmlto] + docs_xmlto_search_flags + [
|
||||
'-x', join_paths(doc_stylesheet_srcdir, 'xorg-xhtml.xsl'),
|
||||
'-o', meson.current_build_dir(),
|
||||
'xhtml-nochunks', '@INPUT0@'],
|
||||
build_by_default: true,
|
||||
install: false,
|
||||
)
|
||||
|
||||
if build_docs_pdf
|
||||
foreach format : ['ps', 'pdf']
|
||||
output_fn = basename + '.' + format
|
||||
custom_target(
|
||||
output_fn,
|
||||
output: output_fn,
|
||||
input: [input_xml],
|
||||
command: [xmlto] + docs_xmlto_search_flags + [
|
||||
'-x', join_paths(doc_stylesheet_srcdir, 'xorg-fo.xsl'),
|
||||
'--stringparam', 'img.src.path=' + meson.current_build_dir(),
|
||||
'-o', meson.current_build_dir(),
|
||||
'--with-fop', format, '@INPUT0@'],
|
||||
build_by_default: true,
|
||||
install: false,
|
||||
)
|
||||
endforeach
|
||||
endif
|
||||
endforeach
|
||||
endif
|
||||
|
||||
subdir('dtrace')
|
|
@ -0,0 +1,13 @@
|
|||
noinst_LTLIBRARIES = libdri3.la
|
||||
AM_CFLAGS = \
|
||||
@DIX_CFLAGS@ \
|
||||
@LIBDRM_CFLAGS@
|
||||
|
||||
libdri3_la_SOURCES = \
|
||||
dri3.h \
|
||||
dri3_priv.h \
|
||||
dri3.c \
|
||||
dri3_request.c \
|
||||
dri3_screen.c
|
||||
|
||||
sdk_HEADERS = dri3.h
|
|
@ -16,3 +16,7 @@ if build_dri3
|
|||
dependencies: [ common_dep, libdrm_dep ],
|
||||
)
|
||||
endif
|
||||
|
||||
if build_xorg
|
||||
install_data(hdrs_dri3, install_dir: xorgsdkdir)
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
noinst_LTLIBRARIES = libexa.la
|
||||
|
||||
if XORG
|
||||
sdk_HEADERS = exa.h
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS = $(XORG_INCS)
|
||||
|
||||
AM_CFLAGS = $(XORG_CFLAGS) $(DIX_CFLAGS)
|
||||
|
||||
libexa_la_SOURCES = \
|
||||
exa.c \
|
||||
exa.h \
|
||||
exa_classic.c \
|
||||
exa_migration_classic.c \
|
||||
exa_driver.c \
|
||||
exa_mixed.c \
|
||||
exa_migration_mixed.c \
|
||||
exa_accel.c \
|
||||
exa_glyphs.c \
|
||||
exa_offscreen.c \
|
||||
exa_render.c \
|
||||
exa_priv.h \
|
||||
exa_unaccel.c
|
|
@ -0,0 +1,820 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (C) 2000 Keith Packard
|
||||
* 2004 Eric Anholt
|
||||
* 2005 Zack Rusin
|
||||
*
|
||||
* 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 copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* This is the header containing the public API of EXA for exa drivers.
|
||||
*/
|
||||
|
||||
#ifndef EXA_H
|
||||
#define EXA_H
|
||||
|
||||
#include "scrnintstr.h"
|
||||
#include "pixmapstr.h"
|
||||
#include "windowstr.h"
|
||||
#include "gcstruct.h"
|
||||
#include "picturestr.h"
|
||||
#include "fb.h"
|
||||
|
||||
#define EXA_VERSION_MAJOR 2
|
||||
#define EXA_VERSION_MINOR 6
|
||||
#define EXA_VERSION_RELEASE 0
|
||||
|
||||
typedef struct _ExaOffscreenArea ExaOffscreenArea;
|
||||
|
||||
typedef void (*ExaOffscreenSaveProc) (ScreenPtr pScreen,
|
||||
ExaOffscreenArea * area);
|
||||
|
||||
typedef enum _ExaOffscreenState {
|
||||
ExaOffscreenAvail,
|
||||
ExaOffscreenRemovable,
|
||||
ExaOffscreenLocked
|
||||
} ExaOffscreenState;
|
||||
|
||||
struct _ExaOffscreenArea {
|
||||
int base_offset; /* allocation base */
|
||||
int offset; /* aligned offset */
|
||||
int size; /* total allocation size */
|
||||
unsigned last_use;
|
||||
void *privData;
|
||||
|
||||
ExaOffscreenSaveProc save;
|
||||
|
||||
ExaOffscreenState state;
|
||||
|
||||
ExaOffscreenArea *next;
|
||||
|
||||
unsigned eviction_cost;
|
||||
|
||||
ExaOffscreenArea *prev; /* Double-linked list for defragmentation */
|
||||
int align; /* required alignment */
|
||||
};
|
||||
|
||||
/**
|
||||
* The ExaDriver structure is allocated through exaDriverAlloc(), and then
|
||||
* fllled in by drivers.
|
||||
*/
|
||||
typedef struct _ExaDriver {
|
||||
/**
|
||||
* exa_major and exa_minor should be set by the driver to the version of
|
||||
* EXA which the driver was compiled for (or configures itself at runtime
|
||||
* to support). This allows EXA to extend the structure for new features
|
||||
* without breaking ABI for drivers compiled against older versions.
|
||||
*/
|
||||
int exa_major, exa_minor;
|
||||
|
||||
/**
|
||||
* memoryBase is the address of the beginning of framebuffer memory.
|
||||
* The visible screen should be within memoryBase to memoryBase +
|
||||
* memorySize.
|
||||
*/
|
||||
CARD8 *memoryBase;
|
||||
|
||||
/**
|
||||
* offScreenBase is the offset from memoryBase of the beginning of the area
|
||||
* to be managed by EXA's linear offscreen memory manager.
|
||||
*
|
||||
* In XFree86 DDX drivers, this is probably:
|
||||
* (pScrn->displayWidth * cpp * pScrn->virtualY)
|
||||
*/
|
||||
unsigned long offScreenBase;
|
||||
|
||||
/**
|
||||
* memorySize is the length (in bytes) of framebuffer memory beginning
|
||||
* from memoryBase.
|
||||
*
|
||||
* The offscreen memory manager will manage the area beginning at
|
||||
* (memoryBase + offScreenBase), with a length of (memorySize -
|
||||
* offScreenBase)
|
||||
*
|
||||
* In XFree86 DDX drivers, this is probably (pScrn->videoRam * 1024)
|
||||
*/
|
||||
unsigned long memorySize;
|
||||
|
||||
/**
|
||||
* pixmapOffsetAlign is the byte alignment necessary for pixmap offsets
|
||||
* within framebuffer.
|
||||
*
|
||||
* Hardware typically has a required alignment of offsets, which may or may
|
||||
* not be a power of two. EXA will ensure that pixmaps managed by the
|
||||
* offscreen memory manager meet this alignment requirement.
|
||||
*/
|
||||
int pixmapOffsetAlign;
|
||||
|
||||
/**
|
||||
* pixmapPitchAlign is the byte alignment necessary for pixmap pitches
|
||||
* within the framebuffer.
|
||||
*
|
||||
* Hardware typically has a required alignment of pitches for acceleration.
|
||||
* For 3D hardware, Composite acceleration often requires that source and
|
||||
* mask pixmaps (textures) have a power-of-two pitch, which can be demanded
|
||||
* using EXA_OFFSCREEN_ALIGN_POT. These pitch requirements only apply to
|
||||
* pixmaps managed by the offscreen memory manager. Thus, it is up to the
|
||||
* driver to ensure that the visible screen has an appropriate pitch for
|
||||
* acceleration.
|
||||
*/
|
||||
int pixmapPitchAlign;
|
||||
|
||||
/**
|
||||
* The flags field is bitfield of boolean values controlling EXA's behavior.
|
||||
*
|
||||
* The flags include EXA_OFFSCREEN_PIXMAPS, EXA_OFFSCREEN_ALIGN_POT, and
|
||||
* EXA_TWO_BITBLT_DIRECTIONS.
|
||||
*/
|
||||
int flags;
|
||||
|
||||
/** @{ */
|
||||
/**
|
||||
* maxX controls the X coordinate limitation for rendering from the card.
|
||||
* The driver should never receive a request for rendering beyond maxX
|
||||
* in the X direction from the origin of a pixmap.
|
||||
*/
|
||||
int maxX;
|
||||
|
||||
/**
|
||||
* maxY controls the Y coordinate limitation for rendering from the card.
|
||||
* The driver should never receive a request for rendering beyond maxY
|
||||
* in the Y direction from the origin of a pixmap.
|
||||
*/
|
||||
int maxY;
|
||||
/** @} */
|
||||
|
||||
/* private */
|
||||
ExaOffscreenArea *offScreenAreas;
|
||||
Bool needsSync;
|
||||
int lastMarker;
|
||||
|
||||
/** @name Solid
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* PrepareSolid() sets up the driver for doing a solid fill.
|
||||
* @param pPixmap Destination pixmap
|
||||
* @param alu raster operation
|
||||
* @param planemask write mask for the fill
|
||||
* @param fg "foreground" color for the fill
|
||||
*
|
||||
* This call should set up the driver for doing a series of solid fills
|
||||
* through the Solid() call. The alu raster op is one of the GX*
|
||||
* graphics functions listed in X.h, and typically maps to a similar
|
||||
* single-byte "ROP" setting in all hardware. The planemask controls
|
||||
* which bits of the destination should be affected, and will only represent
|
||||
* the bits up to the depth of pPixmap. The fg is the pixel value of the
|
||||
* foreground color referred to in ROP descriptions.
|
||||
*
|
||||
* Note that many drivers will need to store some of the data in the driver
|
||||
* private record, for sending to the hardware with each drawing command.
|
||||
*
|
||||
* The PrepareSolid() call is required of all drivers, but it may fail for any
|
||||
* reason. Failure results in a fallback to software rendering.
|
||||
*/
|
||||
Bool (*PrepareSolid) (PixmapPtr pPixmap,
|
||||
int alu, Pixel planemask, Pixel fg);
|
||||
|
||||
/**
|
||||
* Solid() performs a solid fill set up in the last PrepareSolid() call.
|
||||
*
|
||||
* @param pPixmap destination pixmap
|
||||
* @param x1 left coordinate
|
||||
* @param y1 top coordinate
|
||||
* @param x2 right coordinate
|
||||
* @param y2 bottom coordinate
|
||||
*
|
||||
* Performs the fill set up by the last PrepareSolid() call, covering the
|
||||
* area from (x1,y1) to (x2,y2) in pPixmap. Note that the coordinates are
|
||||
* in the coordinate space of the destination pixmap, so the driver will
|
||||
* need to set up the hardware's offset and pitch for the destination
|
||||
* coordinates according to the pixmap's offset and pitch within
|
||||
* framebuffer. This likely means using exaGetPixmapOffset() and
|
||||
* exaGetPixmapPitch().
|
||||
*
|
||||
* This call is required if PrepareSolid() ever succeeds.
|
||||
*/
|
||||
void (*Solid) (PixmapPtr pPixmap, int x1, int y1, int x2, int y2);
|
||||
|
||||
/**
|
||||
* DoneSolid() finishes a set of solid fills.
|
||||
*
|
||||
* @param pPixmap destination pixmap.
|
||||
*
|
||||
* The DoneSolid() call is called at the end of a series of consecutive
|
||||
* Solid() calls following a successful PrepareSolid(). This allows drivers
|
||||
* to finish up emitting drawing commands that were buffered, or clean up
|
||||
* state from PrepareSolid().
|
||||
*
|
||||
* This call is required if PrepareSolid() ever succeeds.
|
||||
*/
|
||||
void (*DoneSolid) (PixmapPtr pPixmap);
|
||||
/** @} */
|
||||
|
||||
/** @name Copy
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* PrepareCopy() sets up the driver for doing a copy within video
|
||||
* memory.
|
||||
*
|
||||
* @param pSrcPixmap source pixmap
|
||||
* @param pDstPixmap destination pixmap
|
||||
* @param dx X copy direction
|
||||
* @param dy Y copy direction
|
||||
* @param alu raster operation
|
||||
* @param planemask write mask for the fill
|
||||
*
|
||||
* This call should set up the driver for doing a series of copies from the
|
||||
* the pSrcPixmap to the pDstPixmap. The dx flag will be positive if the
|
||||
* hardware should do the copy from the left to the right, and dy will be
|
||||
* positive if the copy should be done from the top to the bottom. This
|
||||
* is to deal with self-overlapping copies when pSrcPixmap == pDstPixmap.
|
||||
* If your hardware can only support blits that are (left to right, top to
|
||||
* bottom) or (right to left, bottom to top), then you should set
|
||||
* #EXA_TWO_BITBLT_DIRECTIONS, and EXA will break down Copy operations to
|
||||
* ones that meet those requirements. The alu raster op is one of the GX*
|
||||
* graphics functions listed in X.h, and typically maps to a similar
|
||||
* single-byte "ROP" setting in all hardware. The planemask controls which
|
||||
* bits of the destination should be affected, and will only represent the
|
||||
* bits up to the depth of pPixmap.
|
||||
*
|
||||
* Note that many drivers will need to store some of the data in the driver
|
||||
* private record, for sending to the hardware with each drawing command.
|
||||
*
|
||||
* The PrepareCopy() call is required of all drivers, but it may fail for any
|
||||
* reason. Failure results in a fallback to software rendering.
|
||||
*/
|
||||
Bool (*PrepareCopy) (PixmapPtr pSrcPixmap,
|
||||
PixmapPtr pDstPixmap,
|
||||
int dx, int dy, int alu, Pixel planemask);
|
||||
|
||||
/**
|
||||
* Copy() performs a copy set up in the last PrepareCopy call.
|
||||
*
|
||||
* @param pDstPixmap destination pixmap
|
||||
* @param srcX source X coordinate
|
||||
* @param srcY source Y coordinate
|
||||
* @param dstX destination X coordinate
|
||||
* @param dstY destination Y coordinate
|
||||
* @param width width of the rectangle to be copied
|
||||
* @param height height of the rectangle to be copied.
|
||||
*
|
||||
* Performs the copy set up by the last PrepareCopy() call, copying the
|
||||
* rectangle from (srcX, srcY) to (srcX + width, srcY + width) in the source
|
||||
* pixmap to the same-sized rectangle at (dstX, dstY) in the destination
|
||||
* pixmap. Those rectangles may overlap in memory, if
|
||||
* pSrcPixmap == pDstPixmap. Note that this call does not receive the
|
||||
* pSrcPixmap as an argument -- if it's needed in this function, it should
|
||||
* be stored in the driver private during PrepareCopy(). As with Solid(),
|
||||
* the coordinates are in the coordinate space of each pixmap, so the driver
|
||||
* will need to set up source and destination pitches and offsets from those
|
||||
* pixmaps, probably using exaGetPixmapOffset() and exaGetPixmapPitch().
|
||||
*
|
||||
* This call is required if PrepareCopy ever succeeds.
|
||||
*/
|
||||
void (*Copy) (PixmapPtr pDstPixmap,
|
||||
int srcX,
|
||||
int srcY, int dstX, int dstY, int width, int height);
|
||||
|
||||
/**
|
||||
* DoneCopy() finishes a set of copies.
|
||||
*
|
||||
* @param pPixmap destination pixmap.
|
||||
*
|
||||
* The DoneCopy() call is called at the end of a series of consecutive
|
||||
* Copy() calls following a successful PrepareCopy(). This allows drivers
|
||||
* to finish up emitting drawing commands that were buffered, or clean up
|
||||
* state from PrepareCopy().
|
||||
*
|
||||
* This call is required if PrepareCopy() ever succeeds.
|
||||
*/
|
||||
void (*DoneCopy) (PixmapPtr pDstPixmap);
|
||||
/** @} */
|
||||
|
||||
/** @name Composite
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* CheckComposite() checks to see if a composite operation could be
|
||||
* accelerated.
|
||||
*
|
||||
* @param op Render operation
|
||||
* @param pSrcPicture source Picture
|
||||
* @param pMaskPicture mask picture
|
||||
* @param pDstPicture destination Picture
|
||||
*
|
||||
* The CheckComposite() call checks if the driver could handle acceleration
|
||||
* of op with the given source, mask, and destination pictures. This allows
|
||||
* drivers to check source and destination formats, supported operations,
|
||||
* transformations, and component alpha state, and send operations it can't
|
||||
* support to software rendering early on. This avoids costly pixmap
|
||||
* migration to the wrong places when the driver can't accelerate
|
||||
* operations. Note that because migration hasn't happened, the driver
|
||||
* can't know during CheckComposite() what the offsets and pitches of the
|
||||
* pixmaps are going to be.
|
||||
*
|
||||
* See PrepareComposite() for more details on likely issues that drivers
|
||||
* will have in accelerating Composite operations.
|
||||
*
|
||||
* The CheckComposite() call is recommended if PrepareComposite() is
|
||||
* implemented, but is not required.
|
||||
*/
|
||||
Bool (*CheckComposite) (int op,
|
||||
PicturePtr pSrcPicture,
|
||||
PicturePtr pMaskPicture, PicturePtr pDstPicture);
|
||||
|
||||
/**
|
||||
* PrepareComposite() sets up the driver for doing a Composite operation
|
||||
* described in the Render extension protocol spec.
|
||||
*
|
||||
* @param op Render operation
|
||||
* @param pSrcPicture source Picture
|
||||
* @param pMaskPicture mask picture
|
||||
* @param pDstPicture destination Picture
|
||||
* @param pSrc source pixmap
|
||||
* @param pMask mask pixmap
|
||||
* @param pDst destination pixmap
|
||||
*
|
||||
* This call should set up the driver for doing a series of Composite
|
||||
* operations, as described in the Render protocol spec, with the given
|
||||
* pSrcPicture, pMaskPicture, and pDstPicture. The pSrc, pMask, and
|
||||
* pDst are the pixmaps containing the pixel data, and should be used for
|
||||
* setting the offset and pitch used for the coordinate spaces for each of
|
||||
* the Pictures.
|
||||
*
|
||||
* Notes on interpreting Picture structures:
|
||||
* - The Picture structures will always have a valid pDrawable.
|
||||
* - The Picture structures will never have alphaMap set.
|
||||
* - The mask Picture (and therefore pMask) may be NULL, in which case the
|
||||
* operation is simply src OP dst instead of src IN mask OP dst, and
|
||||
* mask coordinates should be ignored.
|
||||
* - pMarkPicture may have componentAlpha set, which greatly changes
|
||||
* the behavior of the Composite operation. componentAlpha has no effect
|
||||
* when set on pSrcPicture or pDstPicture.
|
||||
* - The source and mask Pictures may have a transformation set
|
||||
* (Picture->transform != NULL), which means that the source coordinates
|
||||
* should be transformed by that transformation, resulting in scaling,
|
||||
* rotation, etc. The PictureTransformPoint() call can transform
|
||||
* coordinates for you. Transforms have no effect on Pictures when used
|
||||
* as a destination.
|
||||
* - The source and mask pictures may have a filter set. PictFilterNearest
|
||||
* and PictFilterBilinear are defined in the Render protocol, but others
|
||||
* may be encountered, and must be handled correctly (usually by
|
||||
* PrepareComposite failing, and falling back to software). Filters have
|
||||
* no effect on Pictures when used as a destination.
|
||||
* - The source and mask Pictures may have repeating set, which must be
|
||||
* respected. Many chipsets will be unable to support repeating on
|
||||
* pixmaps that have a width or height that is not a power of two.
|
||||
*
|
||||
* If your hardware can't support source pictures (textures) with
|
||||
* non-power-of-two pitches, you should set #EXA_OFFSCREEN_ALIGN_POT.
|
||||
*
|
||||
* Note that many drivers will need to store some of the data in the driver
|
||||
* private record, for sending to the hardware with each drawing command.
|
||||
*
|
||||
* The PrepareComposite() call is not required. However, it is highly
|
||||
* recommended for performance of antialiased font rendering and performance
|
||||
* of cairo applications. Failure results in a fallback to software
|
||||
* rendering.
|
||||
*/
|
||||
Bool (*PrepareComposite) (int op,
|
||||
PicturePtr pSrcPicture,
|
||||
PicturePtr pMaskPicture,
|
||||
PicturePtr pDstPicture,
|
||||
PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst);
|
||||
|
||||
/**
|
||||
* Composite() performs a Composite operation set up in the last
|
||||
* PrepareComposite() call.
|
||||
*
|
||||
* @param pDstPixmap destination pixmap
|
||||
* @param srcX source X coordinate
|
||||
* @param srcY source Y coordinate
|
||||
* @param maskX source X coordinate
|
||||
* @param maskY source Y coordinate
|
||||
* @param dstX destination X coordinate
|
||||
* @param dstY destination Y coordinate
|
||||
* @param width destination rectangle width
|
||||
* @param height destination rectangle height
|
||||
*
|
||||
* Performs the Composite operation set up by the last PrepareComposite()
|
||||
* call, to the rectangle from (dstX, dstY) to (dstX + width, dstY + height)
|
||||
* in the destination Pixmap. Note that if a transformation was set on
|
||||
* the source or mask Pictures, the source rectangles may not be the same
|
||||
* size as the destination rectangles and filtering. Getting the coordinate
|
||||
* transformation right at the subpixel level can be tricky, and rendercheck
|
||||
* can test this for you.
|
||||
*
|
||||
* This call is required if PrepareComposite() ever succeeds.
|
||||
*/
|
||||
void (*Composite) (PixmapPtr pDst,
|
||||
int srcX,
|
||||
int srcY,
|
||||
int maskX,
|
||||
int maskY, int dstX, int dstY, int width, int height);
|
||||
|
||||
/**
|
||||
* DoneComposite() finishes a set of Composite operations.
|
||||
*
|
||||
* @param pPixmap destination pixmap.
|
||||
*
|
||||
* The DoneComposite() call is called at the end of a series of consecutive
|
||||
* Composite() calls following a successful PrepareComposite(). This allows
|
||||
* drivers to finish up emitting drawing commands that were buffered, or
|
||||
* clean up state from PrepareComposite().
|
||||
*
|
||||
* This call is required if PrepareComposite() ever succeeds.
|
||||
*/
|
||||
void (*DoneComposite) (PixmapPtr pDst);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* UploadToScreen() loads a rectangle of data from src into pDst.
|
||||
*
|
||||
* @param pDst destination pixmap
|
||||
* @param x destination X coordinate.
|
||||
* @param y destination Y coordinate
|
||||
* @param width width of the rectangle to be copied
|
||||
* @param height height of the rectangle to be copied
|
||||
* @param src pointer to the beginning of the source data
|
||||
* @param src_pitch pitch (in bytes) of the lines of source data.
|
||||
*
|
||||
* UploadToScreen() copies data in system memory beginning at src (with
|
||||
* pitch src_pitch) into the destination pixmap from (x, y) to
|
||||
* (x + width, y + height). This is typically done with hostdata uploads,
|
||||
* where the CPU sets up a blit command on the hardware with instructions
|
||||
* that the blit data will be fed through some sort of aperture on the card.
|
||||
*
|
||||
* If UploadToScreen() is performed asynchronously, it is up to the driver
|
||||
* to call exaMarkSync(). This is in contrast to most other acceleration
|
||||
* calls in EXA.
|
||||
*
|
||||
* UploadToScreen() can aid in pixmap migration, but is most important for
|
||||
* the performance of exaGlyphs() (antialiased font drawing) by allowing
|
||||
* pipelining of data uploads, avoiding a sync of the card after each glyph.
|
||||
*
|
||||
* @return TRUE if the driver successfully uploaded the data. FALSE
|
||||
* indicates that EXA should fall back to doing the upload in software.
|
||||
*
|
||||
* UploadToScreen() is not required, but is recommended if Composite
|
||||
* acceleration is supported.
|
||||
*/
|
||||
Bool (*UploadToScreen) (PixmapPtr pDst,
|
||||
int x,
|
||||
int y, int w, int h, char *src, int src_pitch);
|
||||
|
||||
/**
|
||||
* UploadToScratch() is no longer used and will be removed next time the EXA
|
||||
* major version needs to be bumped.
|
||||
*/
|
||||
Bool (*UploadToScratch) (PixmapPtr pSrc, PixmapPtr pDst);
|
||||
|
||||
/**
|
||||
* DownloadFromScreen() loads a rectangle of data from pSrc into dst
|
||||
*
|
||||
* @param pSrc source pixmap
|
||||
* @param x source X coordinate.
|
||||
* @param y source Y coordinate
|
||||
* @param width width of the rectangle to be copied
|
||||
* @param height height of the rectangle to be copied
|
||||
* @param dst pointer to the beginning of the destination data
|
||||
* @param dst_pitch pitch (in bytes) of the lines of destination data.
|
||||
*
|
||||
* DownloadFromScreen() copies data from offscreen memory in pSrc from
|
||||
* (x, y) to (x + width, y + height), to system memory starting at
|
||||
* dst (with pitch dst_pitch). This would usually be done
|
||||
* using scatter-gather DMA, supported by a DRM call, or by blitting to AGP
|
||||
* and then synchronously reading from AGP. Because the implementation
|
||||
* might be synchronous, EXA leaves it up to the driver to call
|
||||
* exaMarkSync() if DownloadFromScreen() was asynchronous. This is in
|
||||
* contrast to most other acceleration calls in EXA.
|
||||
*
|
||||
* DownloadFromScreen() can aid in the largest bottleneck in pixmap
|
||||
* migration, which is the read from framebuffer when evicting pixmaps from
|
||||
* framebuffer memory. Thus, it is highly recommended, even though
|
||||
* implementations are typically complicated.
|
||||
*
|
||||
* @return TRUE if the driver successfully downloaded the data. FALSE
|
||||
* indicates that EXA should fall back to doing the download in software.
|
||||
*
|
||||
* DownloadFromScreen() is not required, but is highly recommended.
|
||||
*/
|
||||
Bool (*DownloadFromScreen) (PixmapPtr pSrc,
|
||||
int x, int y,
|
||||
int w, int h, char *dst, int dst_pitch);
|
||||
|
||||
/**
|
||||
* MarkSync() requests that the driver mark a synchronization point,
|
||||
* returning an driver-defined integer marker which could be requested for
|
||||
* synchronization to later in WaitMarker(). This might be used in the
|
||||
* future to avoid waiting for full hardware stalls before accessing pixmap
|
||||
* data with the CPU, but is not important in the current incarnation of
|
||||
* EXA.
|
||||
*
|
||||
* Note that drivers should call exaMarkSync() when they have done some
|
||||
* acceleration, rather than their own MarkSync() handler, as otherwise EXA
|
||||
* will be unaware of the driver's acceleration and not sync to it during
|
||||
* fallbacks.
|
||||
*
|
||||
* MarkSync() is optional.
|
||||
*/
|
||||
int (*MarkSync) (ScreenPtr pScreen);
|
||||
|
||||
/**
|
||||
* WaitMarker() waits for all rendering before the given marker to have
|
||||
* completed. If the driver does not implement MarkSync(), marker is
|
||||
* meaningless, and all rendering by the hardware should be completed before
|
||||
* WaitMarker() returns.
|
||||
*
|
||||
* Note that drivers should call exaWaitSync() to wait for all acceleration
|
||||
* to finish, as otherwise EXA will be unaware of the driver having
|
||||
* synchronized, resulting in excessive WaitMarker() calls.
|
||||
*
|
||||
* WaitMarker() is required of all drivers.
|
||||
*/
|
||||
void (*WaitMarker) (ScreenPtr pScreen, int marker);
|
||||
|
||||
/** @{ */
|
||||
/**
|
||||
* PrepareAccess() is called before CPU access to an offscreen pixmap.
|
||||
*
|
||||
* @param pPix the pixmap being accessed
|
||||
* @param index the index of the pixmap being accessed.
|
||||
*
|
||||
* PrepareAccess() will be called before CPU access to an offscreen pixmap.
|
||||
* This can be used to set up hardware surfaces for byteswapping or
|
||||
* untiling, or to adjust the pixmap's devPrivate.ptr for the purpose of
|
||||
* making CPU access use a different aperture.
|
||||
*
|
||||
* The index is one of #EXA_PREPARE_DEST, #EXA_PREPARE_SRC,
|
||||
* #EXA_PREPARE_MASK, #EXA_PREPARE_AUX_DEST, #EXA_PREPARE_AUX_SRC, or
|
||||
* #EXA_PREPARE_AUX_MASK. Since only up to #EXA_NUM_PREPARE_INDICES pixmaps
|
||||
* will have PrepareAccess() called on them per operation, drivers can have
|
||||
* a small, statically-allocated space to maintain state for PrepareAccess()
|
||||
* and FinishAccess() in. Note that PrepareAccess() is only called once per
|
||||
* pixmap and operation, regardless of whether the pixmap is used as a
|
||||
* destination and/or source, and the index may not reflect the usage.
|
||||
*
|
||||
* PrepareAccess() may fail. An example might be the case of hardware that
|
||||
* can set up 1 or 2 surfaces for CPU access, but not 3. If PrepareAccess()
|
||||
* fails, EXA will migrate the pixmap to system memory.
|
||||
* DownloadFromScreen() must be implemented and must not fail if a driver
|
||||
* wishes to fail in PrepareAccess(). PrepareAccess() must not fail when
|
||||
* pPix is the visible screen, because the visible screen can not be
|
||||
* migrated.
|
||||
*
|
||||
* @return TRUE if PrepareAccess() successfully prepared the pixmap for CPU
|
||||
* drawing.
|
||||
* @return FALSE if PrepareAccess() is unsuccessful and EXA should use
|
||||
* DownloadFromScreen() to migate the pixmap out.
|
||||
*/
|
||||
Bool (*PrepareAccess) (PixmapPtr pPix, int index);
|
||||
|
||||
/**
|
||||
* FinishAccess() is called after CPU access to an offscreen pixmap.
|
||||
*
|
||||
* @param pPix the pixmap being accessed
|
||||
* @param index the index of the pixmap being accessed.
|
||||
*
|
||||
* FinishAccess() will be called after finishing CPU access of an offscreen
|
||||
* pixmap set up by PrepareAccess(). Note that the FinishAccess() will not be
|
||||
* called if PrepareAccess() failed and the pixmap was migrated out.
|
||||
*/
|
||||
void (*FinishAccess) (PixmapPtr pPix, int index);
|
||||
|
||||
/**
|
||||
* PixmapIsOffscreen() is an optional driver replacement to
|
||||
* exaPixmapHasGpuCopy(). Set to NULL if you want the standard behaviour
|
||||
* of exaPixmapHasGpuCopy().
|
||||
*
|
||||
* @param pPix the pixmap
|
||||
* @return TRUE if the given drawable is in framebuffer memory.
|
||||
*
|
||||
* exaPixmapHasGpuCopy() is used to determine if a pixmap is in offscreen
|
||||
* memory, meaning that acceleration could probably be done to it, and that it
|
||||
* will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it
|
||||
* with the CPU.
|
||||
*
|
||||
*
|
||||
*/
|
||||
Bool (*PixmapIsOffscreen) (PixmapPtr pPix);
|
||||
|
||||
/** @name PrepareAccess() and FinishAccess() indices
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* EXA_PREPARE_DEST is the index for a pixmap that may be drawn to or
|
||||
* read from.
|
||||
*/
|
||||
#define EXA_PREPARE_DEST 0
|
||||
/**
|
||||
* EXA_PREPARE_SRC is the index for a pixmap that may be read from
|
||||
*/
|
||||
#define EXA_PREPARE_SRC 1
|
||||
/**
|
||||
* EXA_PREPARE_SRC is the index for a second pixmap that may be read
|
||||
* from.
|
||||
*/
|
||||
#define EXA_PREPARE_MASK 2
|
||||
/**
|
||||
* EXA_PREPARE_AUX* are additional indices for other purposes, e.g.
|
||||
* separate alpha maps with Composite operations.
|
||||
*/
|
||||
#define EXA_PREPARE_AUX_DEST 3
|
||||
#define EXA_PREPARE_AUX_SRC 4
|
||||
#define EXA_PREPARE_AUX_MASK 5
|
||||
#define EXA_NUM_PREPARE_INDICES 6
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* maxPitchPixels controls the pitch limitation for rendering from
|
||||
* the card.
|
||||
* The driver should never receive a request for rendering a pixmap
|
||||
* that has a pitch (in pixels) beyond maxPitchPixels.
|
||||
*
|
||||
* Setting this field is optional -- if your hardware doesn't have
|
||||
* a pitch limitation in pixels, don't set this. If neither this value
|
||||
* nor maxPitchBytes is set, then maxPitchPixels is set to maxX.
|
||||
* If set, it must not be smaller than maxX.
|
||||
*
|
||||
* @sa maxPitchBytes
|
||||
*/
|
||||
int maxPitchPixels;
|
||||
|
||||
/**
|
||||
* maxPitchBytes controls the pitch limitation for rendering from
|
||||
* the card.
|
||||
* The driver should never receive a request for rendering a pixmap
|
||||
* that has a pitch (in bytes) beyond maxPitchBytes.
|
||||
*
|
||||
* Setting this field is optional -- if your hardware doesn't have
|
||||
* a pitch limitation in bytes, don't set this.
|
||||
* If set, it must not be smaller than maxX * 4.
|
||||
* There's no default value for maxPitchBytes.
|
||||
*
|
||||
* @sa maxPitchPixels
|
||||
*/
|
||||
int maxPitchBytes;
|
||||
|
||||
/* Hooks to allow driver to its own pixmap memory management */
|
||||
void *(*CreatePixmap) (ScreenPtr pScreen, int size, int align);
|
||||
void (*DestroyPixmap) (ScreenPtr pScreen, void *driverPriv);
|
||||
/**
|
||||
* Returning a pixmap with non-NULL devPrivate.ptr implies a pixmap which is
|
||||
* not offscreen, which will never be accelerated and Prepare/FinishAccess won't
|
||||
* be called.
|
||||
*/
|
||||
Bool (*ModifyPixmapHeader) (PixmapPtr pPixmap, int width, int height,
|
||||
int depth, int bitsPerPixel, int devKind,
|
||||
void *pPixData);
|
||||
|
||||
/* hooks for drivers with tiling support:
|
||||
* driver MUST fill out new_fb_pitch with valid pitch of pixmap
|
||||
*/
|
||||
void *(*CreatePixmap2) (ScreenPtr pScreen, int width, int height,
|
||||
int depth, int usage_hint, int bitsPerPixel,
|
||||
int *new_fb_pitch);
|
||||
/** @} */
|
||||
Bool (*SharePixmapBacking)(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p);
|
||||
|
||||
Bool (*SetSharedPixmapBacking)(PixmapPtr pPixmap, void *handle);
|
||||
|
||||
} ExaDriverRec, *ExaDriverPtr;
|
||||
|
||||
/** @name EXA driver flags
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* EXA_OFFSCREEN_PIXMAPS indicates to EXA that the driver can support
|
||||
* offscreen pixmaps.
|
||||
*/
|
||||
#define EXA_OFFSCREEN_PIXMAPS (1 << 0)
|
||||
|
||||
/**
|
||||
* EXA_OFFSCREEN_ALIGN_POT indicates to EXA that the driver needs pixmaps
|
||||
* to have a power-of-two pitch.
|
||||
*/
|
||||
#define EXA_OFFSCREEN_ALIGN_POT (1 << 1)
|
||||
|
||||
/**
|
||||
* EXA_TWO_BITBLT_DIRECTIONS indicates to EXA that the driver can only
|
||||
* support copies that are (left-to-right, top-to-bottom) or
|
||||
* (right-to-left, bottom-to-top).
|
||||
*/
|
||||
#define EXA_TWO_BITBLT_DIRECTIONS (1 << 2)
|
||||
|
||||
/**
|
||||
* EXA_HANDLES_PIXMAPS indicates to EXA that the driver can handle
|
||||
* all pixmap addressing and migration.
|
||||
*/
|
||||
#define EXA_HANDLES_PIXMAPS (1 << 3)
|
||||
|
||||
/**
|
||||
* EXA_SUPPORTS_PREPARE_AUX indicates to EXA that the driver can handle the
|
||||
* EXA_PREPARE_AUX* indices in the Prepare/FinishAccess hooks. If there are no
|
||||
* such hooks, this flag has no effect.
|
||||
*/
|
||||
#define EXA_SUPPORTS_PREPARE_AUX (1 << 4)
|
||||
|
||||
/**
|
||||
* EXA_SUPPORTS_OFFSCREEN_OVERLAPS indicates to EXA that the driver Copy hooks
|
||||
* can handle the source and destination occupying overlapping offscreen memory
|
||||
* areas. This allows the offscreen memory defragmentation code to defragment
|
||||
* areas where the defragmented position overlaps the fragmented position.
|
||||
*
|
||||
* Typically this is supported by traditional 2D engines but not by 3D engines.
|
||||
*/
|
||||
#define EXA_SUPPORTS_OFFSCREEN_OVERLAPS (1 << 5)
|
||||
|
||||
/**
|
||||
* EXA_MIXED_PIXMAPS will hide unacceleratable pixmaps from drivers and manage the
|
||||
* problem known software fallbacks like trapezoids. This only migrates pixmaps one way
|
||||
* into a driver pixmap and then pins it.
|
||||
*/
|
||||
#define EXA_MIXED_PIXMAPS (1 << 6)
|
||||
|
||||
/** @} */
|
||||
|
||||
/* in exa.c */
|
||||
extern _X_EXPORT ExaDriverPtr exaDriverAlloc(void);
|
||||
|
||||
extern _X_EXPORT Bool
|
||||
exaDriverInit(ScreenPtr pScreen, ExaDriverPtr pScreenInfo);
|
||||
|
||||
extern _X_EXPORT void
|
||||
exaDriverFini(ScreenPtr pScreen);
|
||||
|
||||
extern _X_EXPORT void
|
||||
exaMarkSync(ScreenPtr pScreen);
|
||||
extern _X_EXPORT void
|
||||
exaWaitSync(ScreenPtr pScreen);
|
||||
|
||||
extern _X_EXPORT unsigned long
|
||||
exaGetPixmapOffset(PixmapPtr pPix);
|
||||
|
||||
extern _X_EXPORT unsigned long
|
||||
exaGetPixmapPitch(PixmapPtr pPix);
|
||||
|
||||
extern _X_EXPORT unsigned long
|
||||
exaGetPixmapSize(PixmapPtr pPix);
|
||||
|
||||
extern _X_EXPORT void *exaGetPixmapDriverPrivate(PixmapPtr p);
|
||||
|
||||
/* in exa_offscreen.c */
|
||||
extern _X_EXPORT ExaOffscreenArea *exaOffscreenAlloc(ScreenPtr pScreen,
|
||||
int size, int align,
|
||||
Bool locked,
|
||||
ExaOffscreenSaveProc save,
|
||||
void *privData);
|
||||
|
||||
extern _X_EXPORT ExaOffscreenArea *exaOffscreenFree(ScreenPtr pScreen,
|
||||
ExaOffscreenArea * area);
|
||||
|
||||
extern _X_EXPORT void
|
||||
ExaOffscreenMarkUsed(PixmapPtr pPixmap);
|
||||
|
||||
extern _X_EXPORT void
|
||||
exaEnableDisableFBAccess(ScreenPtr pScreen, Bool enable);
|
||||
|
||||
extern _X_EXPORT Bool
|
||||
exaDrawableIsOffscreen(DrawablePtr pDrawable);
|
||||
|
||||
/* in exa.c */
|
||||
extern _X_EXPORT void
|
||||
exaMoveInPixmap(PixmapPtr pPixmap);
|
||||
|
||||
extern _X_EXPORT void
|
||||
exaMoveOutPixmap(PixmapPtr pPixmap);
|
||||
|
||||
/* in exa_unaccel.c */
|
||||
extern _X_EXPORT CARD32
|
||||
exaGetPixmapFirstPixel(PixmapPtr pPixmap);
|
||||
|
||||
/**
|
||||
* Returns TRUE if the given planemask covers all the significant bits in the
|
||||
* pixel values for pDrawable.
|
||||
*/
|
||||
#define EXA_PM_IS_SOLID(_pDrawable, _pm) \
|
||||
(((_pm) & FbFullMask((_pDrawable)->depth)) == \
|
||||
FbFullMask((_pDrawable)->depth))
|
||||
|
||||
#endif /* EXA_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Copyright © 2009 Maarten Maathuis
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "exa_priv.h"
|
||||
#include "exa.h"
|
||||
|
||||
/* This file holds the classic exa specific implementation. */
|
||||
|
||||
static _X_INLINE void *
|
||||
ExaGetPixmapAddress(PixmapPtr p)
|
||||
{
|
||||
ExaPixmapPriv(p);
|
||||
|
||||
if (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr)
|
||||
return pExaPixmap->fb_ptr;
|
||||
else
|
||||
return pExaPixmap->sys_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* exaCreatePixmap() creates a new pixmap.
|
||||
*
|
||||
* If width and height are 0, this won't be a full-fledged pixmap and it will
|
||||
* get ModifyPixmapHeader() called on it later. So, we mark it as pinned, because
|
||||
* ModifyPixmapHeader() would break migration. These types of pixmaps are used
|
||||
* for scratch pixmaps, or to represent the visible screen.
|
||||
*/
|
||||
PixmapPtr
|
||||
exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
|
||||
unsigned usage_hint)
|
||||
{
|
||||
PixmapPtr pPixmap;
|
||||
ExaPixmapPrivPtr pExaPixmap;
|
||||
BoxRec box;
|
||||
int bpp;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
if (w > 32767 || h > 32767)
|
||||
return NullPixmap;
|
||||
|
||||
swap(pExaScr, pScreen, CreatePixmap);
|
||||
pPixmap = pScreen->CreatePixmap(pScreen, w, h, depth, usage_hint);
|
||||
swap(pExaScr, pScreen, CreatePixmap);
|
||||
|
||||
if (!pPixmap)
|
||||
return NULL;
|
||||
|
||||
pExaPixmap = ExaGetPixmapPriv(pPixmap);
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
|
||||
bpp = pPixmap->drawable.bitsPerPixel;
|
||||
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
/* Scratch pixmaps may have w/h equal to zero, and may not be
|
||||
* migrated.
|
||||
*/
|
||||
if (!w || !h)
|
||||
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
|
||||
else
|
||||
pExaPixmap->score = EXA_PIXMAP_SCORE_INIT;
|
||||
|
||||
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
|
||||
pExaPixmap->sys_pitch = pPixmap->devKind;
|
||||
|
||||
pPixmap->devPrivate.ptr = NULL;
|
||||
pExaPixmap->use_gpu_copy = FALSE;
|
||||
|
||||
pExaPixmap->fb_ptr = NULL;
|
||||
exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
|
||||
pExaPixmap->fb_size = pExaPixmap->fb_pitch * h;
|
||||
|
||||
if (pExaPixmap->fb_pitch > 131071) {
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
pScreen->DestroyPixmap(pPixmap);
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set up damage tracking */
|
||||
pExaPixmap->pDamage = DamageCreate(NULL, NULL,
|
||||
DamageReportNone, TRUE,
|
||||
pScreen, pPixmap);
|
||||
|
||||
if (pExaPixmap->pDamage == NULL) {
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
pScreen->DestroyPixmap(pPixmap);
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
|
||||
/* This ensures that pending damage reflects the current operation. */
|
||||
/* This is used by exa to optimize migration. */
|
||||
DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
|
||||
|
||||
pExaPixmap->area = NULL;
|
||||
|
||||
/* We set the initial pixmap as completely valid for a simple reason.
|
||||
* Imagine a 1000x1000 pixmap, it has 1 million pixels, 250000 of which
|
||||
* could form single pixel rects as part of a region. Setting the complete region
|
||||
* as valid is a natural defragmentation of the region.
|
||||
*/
|
||||
box.x1 = 0;
|
||||
box.y1 = 0;
|
||||
box.x2 = w;
|
||||
box.y2 = h;
|
||||
RegionInit(&pExaPixmap->validSys, &box, 0);
|
||||
RegionInit(&pExaPixmap->validFB, &box, 0);
|
||||
|
||||
exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
|
||||
|
||||
/* During a fallback we must prepare access. */
|
||||
if (pExaScr->fallback_counter)
|
||||
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
|
||||
|
||||
return pPixmap;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height,
|
||||
int depth, int bitsPerPixel, int devKind,
|
||||
void *pPixData)
|
||||
{
|
||||
ScreenPtr pScreen;
|
||||
ExaScreenPrivPtr pExaScr;
|
||||
ExaPixmapPrivPtr pExaPixmap;
|
||||
Bool ret;
|
||||
|
||||
if (!pPixmap)
|
||||
return FALSE;
|
||||
|
||||
pScreen = pPixmap->drawable.pScreen;
|
||||
pExaScr = ExaGetScreenPriv(pScreen);
|
||||
pExaPixmap = ExaGetPixmapPriv(pPixmap);
|
||||
|
||||
if (pExaPixmap) {
|
||||
if (pPixData)
|
||||
pExaPixmap->sys_ptr = pPixData;
|
||||
|
||||
if (devKind > 0)
|
||||
pExaPixmap->sys_pitch = devKind;
|
||||
|
||||
/* Classic EXA:
|
||||
* - Framebuffer.
|
||||
* - Scratch pixmap with gpu memory.
|
||||
*/
|
||||
if (pExaScr->info->memoryBase && pPixData) {
|
||||
if ((CARD8 *) pPixData >= pExaScr->info->memoryBase &&
|
||||
((CARD8 *) pPixData - pExaScr->info->memoryBase) <
|
||||
pExaScr->info->memorySize) {
|
||||
pExaPixmap->fb_ptr = pPixData;
|
||||
pExaPixmap->fb_pitch = devKind;
|
||||
pExaPixmap->use_gpu_copy = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (width > 0 && height > 0 && bitsPerPixel > 0) {
|
||||
exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
|
||||
|
||||
exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
|
||||
}
|
||||
|
||||
/* Pixmaps subject to ModifyPixmapHeader will be pinned to system or
|
||||
* gpu memory, so there's no need to track damage.
|
||||
*/
|
||||
if (pExaPixmap->pDamage) {
|
||||
DamageDestroy(pExaPixmap->pDamage);
|
||||
pExaPixmap->pDamage = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
swap(pExaScr, pScreen, ModifyPixmapHeader);
|
||||
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
|
||||
bitsPerPixel, devKind, pPixData);
|
||||
swap(pExaScr, pScreen, ModifyPixmapHeader);
|
||||
|
||||
/* Always NULL this, we don't want lingering pointers. */
|
||||
pPixmap->devPrivate.ptr = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaDestroyPixmap_classic(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
Bool ret;
|
||||
|
||||
if (pPixmap->refcnt == 1) {
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
exaDestroyPixmap(pPixmap);
|
||||
|
||||
if (pExaPixmap->area) {
|
||||
DBG_PIXMAP(("-- 0x%p (0x%x) (%dx%d)\n",
|
||||
(void *) pPixmap->drawable.id,
|
||||
ExaGetPixmapPriv(pPixmap)->area->offset,
|
||||
pPixmap->drawable.width, pPixmap->drawable.height));
|
||||
/* Free the offscreen area */
|
||||
exaOffscreenFree(pPixmap->drawable.pScreen, pExaPixmap->area);
|
||||
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
|
||||
pPixmap->devKind = pExaPixmap->sys_pitch;
|
||||
}
|
||||
RegionUninit(&pExaPixmap->validSys);
|
||||
RegionUninit(&pExaPixmap->validFB);
|
||||
}
|
||||
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
ret = pScreen->DestroyPixmap(pPixmap);
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaPixmapPriv(pPixmap);
|
||||
Bool ret;
|
||||
|
||||
if (pExaScr->info->PixmapIsOffscreen) {
|
||||
void *old_ptr = pPixmap->devPrivate.ptr;
|
||||
|
||||
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
|
||||
ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
|
||||
pPixmap->devPrivate.ptr = old_ptr;
|
||||
}
|
||||
else
|
||||
ret = (pExaPixmap->use_gpu_copy && pExaPixmap->fb_ptr);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* Copyright © 2009 Maarten Maathuis
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "exa_priv.h"
|
||||
#include "exa.h"
|
||||
|
||||
/* This file holds the driver allocated pixmaps specific implementation. */
|
||||
|
||||
static _X_INLINE void *
|
||||
ExaGetPixmapAddress(PixmapPtr p)
|
||||
{
|
||||
ExaPixmapPriv(p);
|
||||
|
||||
return pExaPixmap->sys_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* exaCreatePixmap() creates a new pixmap.
|
||||
*
|
||||
* Pixmaps are always marked as pinned, because exa has no control over them.
|
||||
*/
|
||||
PixmapPtr
|
||||
exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
|
||||
unsigned usage_hint)
|
||||
{
|
||||
PixmapPtr pPixmap;
|
||||
ExaPixmapPrivPtr pExaPixmap;
|
||||
int bpp;
|
||||
size_t paddedWidth, datasize;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
if (w > 32767 || h > 32767)
|
||||
return NullPixmap;
|
||||
|
||||
swap(pExaScr, pScreen, CreatePixmap);
|
||||
pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
|
||||
swap(pExaScr, pScreen, CreatePixmap);
|
||||
|
||||
if (!pPixmap)
|
||||
return NULL;
|
||||
|
||||
pExaPixmap = ExaGetPixmapPriv(pPixmap);
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
|
||||
bpp = pPixmap->drawable.bitsPerPixel;
|
||||
|
||||
/* Set this before driver hooks, to allow for driver pixmaps without gpu
|
||||
* memory to back it. These pixmaps have a valid pointer at all times.
|
||||
*/
|
||||
pPixmap->devPrivate.ptr = NULL;
|
||||
|
||||
if (pExaScr->info->CreatePixmap2) {
|
||||
int new_pitch = 0;
|
||||
|
||||
pExaPixmap->driverPriv =
|
||||
pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp,
|
||||
&new_pitch);
|
||||
paddedWidth = pExaPixmap->fb_pitch = new_pitch;
|
||||
}
|
||||
else {
|
||||
paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
|
||||
if (paddedWidth / 4 > 32767 || h > 32767)
|
||||
return NullPixmap;
|
||||
|
||||
exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
|
||||
|
||||
if (paddedWidth < pExaPixmap->fb_pitch)
|
||||
paddedWidth = pExaPixmap->fb_pitch;
|
||||
datasize = h * paddedWidth;
|
||||
pExaPixmap->driverPriv =
|
||||
pExaScr->info->CreatePixmap(pScreen, datasize, 0);
|
||||
}
|
||||
|
||||
if (!pExaPixmap->driverPriv) {
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
pScreen->DestroyPixmap(pPixmap);
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allow ModifyPixmapHeader to set sys_ptr appropriately. */
|
||||
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
|
||||
pExaPixmap->fb_ptr = NULL;
|
||||
pExaPixmap->pDamage = NULL;
|
||||
pExaPixmap->sys_ptr = NULL;
|
||||
|
||||
(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
|
||||
|
||||
pExaPixmap->area = NULL;
|
||||
|
||||
exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
|
||||
|
||||
pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
|
||||
|
||||
/* During a fallback we must prepare access. */
|
||||
if (pExaScr->fallback_counter)
|
||||
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
|
||||
|
||||
return pPixmap;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height,
|
||||
int depth, int bitsPerPixel, int devKind,
|
||||
void *pPixData)
|
||||
{
|
||||
ScreenPtr pScreen;
|
||||
ExaScreenPrivPtr pExaScr;
|
||||
ExaPixmapPrivPtr pExaPixmap;
|
||||
Bool ret;
|
||||
|
||||
if (!pPixmap)
|
||||
return FALSE;
|
||||
|
||||
pScreen = pPixmap->drawable.pScreen;
|
||||
pExaScr = ExaGetScreenPriv(pScreen);
|
||||
pExaPixmap = ExaGetPixmapPriv(pPixmap);
|
||||
|
||||
if (pExaPixmap) {
|
||||
if (pPixData)
|
||||
pExaPixmap->sys_ptr = pPixData;
|
||||
|
||||
if (devKind > 0)
|
||||
pExaPixmap->sys_pitch = devKind;
|
||||
|
||||
if (width > 0 && height > 0 && bitsPerPixel > 0) {
|
||||
exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
|
||||
|
||||
exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
if (pExaScr->info->ModifyPixmapHeader) {
|
||||
ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
|
||||
bitsPerPixel, devKind,
|
||||
pPixData);
|
||||
/* For EXA_HANDLES_PIXMAPS, we set pPixData to NULL.
|
||||
* If pPixmap->devPrivate.ptr is non-NULL, then we've got a
|
||||
* !has_gpu_copy pixmap. We need to store the pointer,
|
||||
* because PrepareAccess won't be called.
|
||||
*/
|
||||
if (!pPixData && pPixmap->devPrivate.ptr && pPixmap->devKind) {
|
||||
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
|
||||
pExaPixmap->sys_pitch = pPixmap->devKind;
|
||||
}
|
||||
if (ret == TRUE)
|
||||
goto out;
|
||||
}
|
||||
|
||||
swap(pExaScr, pScreen, ModifyPixmapHeader);
|
||||
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
|
||||
bitsPerPixel, devKind, pPixData);
|
||||
swap(pExaScr, pScreen, ModifyPixmapHeader);
|
||||
|
||||
out:
|
||||
/* Always NULL this, we don't want lingering pointers. */
|
||||
pPixmap->devPrivate.ptr = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaDestroyPixmap_driver(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
Bool ret;
|
||||
|
||||
if (pPixmap->refcnt == 1) {
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
exaDestroyPixmap(pPixmap);
|
||||
|
||||
if (pExaPixmap->driverPriv)
|
||||
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
}
|
||||
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
ret = pScreen->DestroyPixmap(pPixmap);
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
void *saved_ptr;
|
||||
Bool ret;
|
||||
|
||||
saved_ptr = pPixmap->devPrivate.ptr;
|
||||
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
|
||||
ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
|
||||
pPixmap->devPrivate.ptr = saved_ptr;
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,839 @@
|
|||
/*
|
||||
* Copyright © 2008 Red Hat, Inc.
|
||||
* Partly based on code Copyright © 2000 SuSE, Inc.
|
||||
*
|
||||
* 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 Red Hat not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. Red Hat makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as is"
|
||||
* without express or implied warranty.
|
||||
*
|
||||
* Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
|
||||
* 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.
|
||||
*
|
||||
* 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 SuSE not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. SuSE makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as is"
|
||||
* without express or implied warranty.
|
||||
*
|
||||
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
|
||||
* 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.
|
||||
*
|
||||
* Author: Owen Taylor <otaylor@fishsoup.net>
|
||||
* Based on code by: Keith Packard
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "exa_priv.h"
|
||||
|
||||
#include "mipict.h"
|
||||
|
||||
#if DEBUG_GLYPH_CACHE
|
||||
#define DBG_GLYPH_CACHE(a) ErrorF a
|
||||
#else
|
||||
#define DBG_GLYPH_CACHE(a)
|
||||
#endif
|
||||
|
||||
/* Width of the pixmaps we use for the caches; this should be less than
|
||||
* max texture size of the driver; this may need to actually come from
|
||||
* the driver.
|
||||
*/
|
||||
#define CACHE_PICTURE_WIDTH 1024
|
||||
|
||||
/* Maximum number of glyphs we buffer on the stack before flushing
|
||||
* rendering to the mask or destination surface.
|
||||
*/
|
||||
#define GLYPH_BUFFER_SIZE 256
|
||||
|
||||
typedef struct {
|
||||
PicturePtr mask;
|
||||
ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE];
|
||||
int count;
|
||||
} ExaGlyphBuffer, *ExaGlyphBufferPtr;
|
||||
|
||||
typedef enum {
|
||||
ExaGlyphSuccess, /* Glyph added to render buffer */
|
||||
ExaGlyphFail, /* out of memory, etc */
|
||||
ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */
|
||||
} ExaGlyphCacheResult;
|
||||
|
||||
void
|
||||
exaGlyphsInit(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
int i = 0;
|
||||
|
||||
memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches));
|
||||
|
||||
pExaScr->glyphCaches[i].format = PICT_a8;
|
||||
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
|
||||
16;
|
||||
i++;
|
||||
pExaScr->glyphCaches[i].format = PICT_a8;
|
||||
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
|
||||
32;
|
||||
i++;
|
||||
pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
|
||||
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
|
||||
16;
|
||||
i++;
|
||||
pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
|
||||
pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight =
|
||||
32;
|
||||
i++;
|
||||
|
||||
assert(i == EXA_NUM_GLYPH_CACHES);
|
||||
|
||||
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
|
||||
pExaScr->glyphCaches[i].columns =
|
||||
CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth;
|
||||
pExaScr->glyphCaches[i].size = 256;
|
||||
pExaScr->glyphCaches[i].hashSize = 557;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
exaUnrealizeGlyphCaches(ScreenPtr pScreen, unsigned int format)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
|
||||
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
|
||||
|
||||
if (cache->format != format)
|
||||
continue;
|
||||
|
||||
if (cache->picture) {
|
||||
FreePicture((void *) cache->picture, (XID) 0);
|
||||
cache->picture = NULL;
|
||||
}
|
||||
|
||||
free(cache->hashEntries);
|
||||
cache->hashEntries = NULL;
|
||||
|
||||
free(cache->glyphs);
|
||||
cache->glyphs = NULL;
|
||||
cache->glyphCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
|
||||
|
||||
/* All caches for a single format share a single pixmap for glyph storage,
|
||||
* allowing mixing glyphs of different sizes without paying a penalty
|
||||
* for switching between mask pixmaps. (Note that for a size of font
|
||||
* right at the border between two sizes, we might be switching for almost
|
||||
* every glyph.)
|
||||
*
|
||||
* This function allocates the storage pixmap, and then fills in the
|
||||
* rest of the allocated structures for all caches with the given format.
|
||||
*/
|
||||
static Bool
|
||||
exaRealizeGlyphCaches(ScreenPtr pScreen, unsigned int format)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
int depth = PIXMAN_FORMAT_DEPTH(format);
|
||||
PictFormatPtr pPictFormat;
|
||||
PixmapPtr pPixmap;
|
||||
PicturePtr pPicture;
|
||||
CARD32 component_alpha;
|
||||
int height;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
pPictFormat = PictureMatchFormat(pScreen, depth, format);
|
||||
if (!pPictFormat)
|
||||
return FALSE;
|
||||
|
||||
/* Compute the total vertical size needed for the format */
|
||||
|
||||
height = 0;
|
||||
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
|
||||
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
|
||||
int rows;
|
||||
|
||||
if (cache->format != format)
|
||||
continue;
|
||||
|
||||
cache->yOffset = height;
|
||||
|
||||
rows = (cache->size + cache->columns - 1) / cache->columns;
|
||||
height += rows * cache->glyphHeight;
|
||||
}
|
||||
|
||||
/* Now allocate the pixmap and picture */
|
||||
pPixmap = (*pScreen->CreatePixmap) (pScreen,
|
||||
CACHE_PICTURE_WIDTH, height, depth, 0);
|
||||
if (!pPixmap)
|
||||
return FALSE;
|
||||
|
||||
component_alpha = NeedsComponent(pPictFormat->format);
|
||||
pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
|
||||
CPComponentAlpha, &component_alpha, serverClient,
|
||||
&error);
|
||||
|
||||
(*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */
|
||||
|
||||
if (!pPicture)
|
||||
return FALSE;
|
||||
|
||||
/* And store the picture in all the caches for the format */
|
||||
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
|
||||
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
|
||||
int j;
|
||||
|
||||
if (cache->format != format)
|
||||
continue;
|
||||
|
||||
cache->picture = pPicture;
|
||||
cache->picture->refcnt++;
|
||||
cache->hashEntries = xallocarray(cache->hashSize, sizeof(int));
|
||||
cache->glyphs = xallocarray(cache->size, sizeof(ExaCachedGlyphRec));
|
||||
cache->glyphCount = 0;
|
||||
|
||||
if (!cache->hashEntries || !cache->glyphs)
|
||||
goto bail;
|
||||
|
||||
for (j = 0; j < cache->hashSize; j++)
|
||||
cache->hashEntries[j] = -1;
|
||||
|
||||
cache->evictionPosition = rand() % cache->size;
|
||||
}
|
||||
|
||||
/* Each cache references the picture individually */
|
||||
FreePicture((void *) pPicture, (XID) 0);
|
||||
return TRUE;
|
||||
|
||||
bail:
|
||||
exaUnrealizeGlyphCaches(pScreen, format);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
exaGlyphsFini(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
|
||||
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
|
||||
|
||||
if (cache->picture)
|
||||
exaUnrealizeGlyphCaches(pScreen, cache->format);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, GlyphPtr pGlyph)
|
||||
{
|
||||
int slot;
|
||||
|
||||
slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
|
||||
|
||||
while (TRUE) { /* hash table can never be full */
|
||||
int entryPos = cache->hashEntries[slot];
|
||||
|
||||
if (entryPos == -1)
|
||||
return -1;
|
||||
|
||||
if (memcmp
|
||||
(pGlyph->sha1, cache->glyphs[entryPos].sha1,
|
||||
sizeof(pGlyph->sha1)) == 0) {
|
||||
return entryPos;
|
||||
}
|
||||
|
||||
slot--;
|
||||
if (slot < 0)
|
||||
slot = cache->hashSize - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, GlyphPtr pGlyph, int pos)
|
||||
{
|
||||
int slot;
|
||||
|
||||
memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1));
|
||||
|
||||
slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
|
||||
|
||||
while (TRUE) { /* hash table can never be full */
|
||||
if (cache->hashEntries[slot] == -1) {
|
||||
cache->hashEntries[slot] = pos;
|
||||
return;
|
||||
}
|
||||
|
||||
slot--;
|
||||
if (slot < 0)
|
||||
slot = cache->hashSize - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, int pos)
|
||||
{
|
||||
int slot;
|
||||
int emptiedSlot = -1;
|
||||
|
||||
slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize;
|
||||
|
||||
while (TRUE) { /* hash table can never be full */
|
||||
int entryPos = cache->hashEntries[slot];
|
||||
|
||||
if (entryPos == -1)
|
||||
return;
|
||||
|
||||
if (entryPos == pos) {
|
||||
cache->hashEntries[slot] = -1;
|
||||
emptiedSlot = slot;
|
||||
}
|
||||
else if (emptiedSlot != -1) {
|
||||
/* See if we can move this entry into the emptied slot, we can't
|
||||
* do that if if entry would have hashed between the current position
|
||||
* and the emptied slot. (taking wrapping into account). Bad positions
|
||||
* are:
|
||||
*
|
||||
* | XXXXXXXXXX |
|
||||
* i j
|
||||
*
|
||||
* |XXX XXXX|
|
||||
* j i
|
||||
*
|
||||
* i - slot, j - emptiedSlot
|
||||
*
|
||||
* (Knuth 6.4R)
|
||||
*/
|
||||
|
||||
int entrySlot =
|
||||
(*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize;
|
||||
|
||||
if (!((entrySlot >= slot && entrySlot < emptiedSlot) ||
|
||||
(emptiedSlot < slot &&
|
||||
(entrySlot < emptiedSlot || entrySlot >= slot)))) {
|
||||
cache->hashEntries[emptiedSlot] = entryPos;
|
||||
cache->hashEntries[slot] = -1;
|
||||
emptiedSlot = slot;
|
||||
}
|
||||
}
|
||||
|
||||
slot--;
|
||||
if (slot < 0)
|
||||
slot = cache->hashSize - 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth)
|
||||
#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight)
|
||||
|
||||
/* The most efficient thing to way to upload the glyph to the screen
|
||||
* is to use the UploadToScreen() driver hook; this allows us to
|
||||
* pipeline glyph uploads and to avoid creating gpu backed pixmaps for
|
||||
* glyphs that we'll never use again.
|
||||
*
|
||||
* If we can't do it with UploadToScreen (because the glyph has a gpu copy,
|
||||
* etc), we fall back to CompositePicture.
|
||||
*
|
||||
* We need to damage the cache pixmap manually in either case because the damage
|
||||
* layer unwrapped the picture screen before calling exaGlyphs.
|
||||
*/
|
||||
static void
|
||||
exaGlyphCacheUploadGlyph(ScreenPtr pScreen,
|
||||
ExaGlyphCachePtr cache, int x, int y, GlyphPtr pGlyph)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
PicturePtr pGlyphPicture = GetGlyphPicture(pGlyph, pScreen);
|
||||
PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
|
||||
|
||||
ExaPixmapPriv(pGlyphPixmap);
|
||||
PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
|
||||
|
||||
if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut ||
|
||||
pExaPixmap->accel_blocked)
|
||||
goto composite;
|
||||
|
||||
/* If the glyph pixmap is already uploaded, no point in doing
|
||||
* things this way */
|
||||
if (exaPixmapHasGpuCopy(pGlyphPixmap))
|
||||
goto composite;
|
||||
|
||||
/* UploadToScreen only works if bpp match */
|
||||
if (pGlyphPixmap->drawable.bitsPerPixel !=
|
||||
pCachePixmap->drawable.bitsPerPixel)
|
||||
goto composite;
|
||||
|
||||
if (pExaScr->do_migration) {
|
||||
ExaMigrationRec pixmaps[1];
|
||||
|
||||
/* cache pixmap must have a gpu copy. */
|
||||
pixmaps[0].as_dst = TRUE;
|
||||
pixmaps[0].as_src = FALSE;
|
||||
pixmaps[0].pPix = pCachePixmap;
|
||||
pixmaps[0].pReg = NULL;
|
||||
exaDoMigration(pixmaps, 1, TRUE);
|
||||
}
|
||||
|
||||
if (!exaPixmapHasGpuCopy(pCachePixmap))
|
||||
goto composite;
|
||||
|
||||
/* x,y are in pixmap coordinates, no need for cache{X,Y}off */
|
||||
if (pExaScr->info->UploadToScreen(pCachePixmap,
|
||||
x,
|
||||
y,
|
||||
pGlyph->info.width,
|
||||
pGlyph->info.height,
|
||||
(char *) pExaPixmap->sys_ptr,
|
||||
pExaPixmap->sys_pitch))
|
||||
goto damage;
|
||||
|
||||
composite:
|
||||
CompositePicture(PictOpSrc,
|
||||
pGlyphPicture,
|
||||
None,
|
||||
cache->picture,
|
||||
0, 0, 0, 0, x, y, pGlyph->info.width, pGlyph->info.height);
|
||||
|
||||
damage:
|
||||
/* The cache pixmap isn't a window, so no need to offset coordinates. */
|
||||
exaPixmapDirty(pCachePixmap,
|
||||
x, y, x + cache->glyphWidth, y + cache->glyphHeight);
|
||||
}
|
||||
|
||||
static ExaGlyphCacheResult
|
||||
exaGlyphCacheBufferGlyph(ScreenPtr pScreen,
|
||||
ExaGlyphCachePtr cache,
|
||||
ExaGlyphBufferPtr buffer,
|
||||
GlyphPtr pGlyph,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pDst,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc,
|
||||
INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst)
|
||||
{
|
||||
ExaCompositeRectPtr rect;
|
||||
int pos;
|
||||
int x, y;
|
||||
|
||||
if (buffer->mask && buffer->mask != cache->picture)
|
||||
return ExaGlyphNeedFlush;
|
||||
|
||||
if (!cache->picture) {
|
||||
if (!exaRealizeGlyphCaches(pScreen, cache->format))
|
||||
return ExaGlyphFail;
|
||||
}
|
||||
|
||||
DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n",
|
||||
cache->glyphWidth, cache->glyphHeight,
|
||||
cache->format == PICT_a8 ? "A" : "ARGB",
|
||||
(long) *(CARD32 *) pGlyph->sha1));
|
||||
|
||||
pos = exaGlyphCacheHashLookup(cache, pGlyph);
|
||||
if (pos != -1) {
|
||||
DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos));
|
||||
x = CACHE_X(pos);
|
||||
y = CACHE_Y(pos);
|
||||
}
|
||||
else {
|
||||
if (cache->glyphCount < cache->size) {
|
||||
/* Space remaining; we fill from the start */
|
||||
pos = cache->glyphCount;
|
||||
x = CACHE_X(pos);
|
||||
y = CACHE_Y(pos);
|
||||
cache->glyphCount++;
|
||||
DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos));
|
||||
|
||||
exaGlyphCacheHashInsert(cache, pGlyph, pos);
|
||||
|
||||
}
|
||||
else {
|
||||
/* Need to evict an entry. We have to see if any glyphs
|
||||
* already in the output buffer were at this position in
|
||||
* the cache
|
||||
*/
|
||||
pos = cache->evictionPosition;
|
||||
x = CACHE_X(pos);
|
||||
y = CACHE_Y(pos);
|
||||
DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos));
|
||||
if (buffer->count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < buffer->count; i++) {
|
||||
if (pSrc ?
|
||||
(buffer->rects[i].xMask == x &&
|
||||
buffer->rects[i].yMask ==
|
||||
y) : (buffer->rects[i].xSrc == x &&
|
||||
buffer->rects[i].ySrc == y)) {
|
||||
DBG_GLYPH_CACHE((" must flush buffer\n"));
|
||||
return ExaGlyphNeedFlush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* OK, we're all set, swap in the new glyph */
|
||||
exaGlyphCacheHashRemove(cache, pos);
|
||||
exaGlyphCacheHashInsert(cache, pGlyph, pos);
|
||||
|
||||
/* And pick a new eviction position */
|
||||
cache->evictionPosition = rand() % cache->size;
|
||||
}
|
||||
|
||||
exaGlyphCacheUploadGlyph(pScreen, cache, x, y, pGlyph);
|
||||
}
|
||||
|
||||
buffer->mask = cache->picture;
|
||||
|
||||
rect = &buffer->rects[buffer->count];
|
||||
|
||||
if (pSrc) {
|
||||
rect->xSrc = xSrc;
|
||||
rect->ySrc = ySrc;
|
||||
rect->xMask = x;
|
||||
rect->yMask = y;
|
||||
}
|
||||
else {
|
||||
rect->xSrc = x;
|
||||
rect->ySrc = y;
|
||||
rect->xMask = 0;
|
||||
rect->yMask = 0;
|
||||
}
|
||||
|
||||
rect->pDst = pDst;
|
||||
rect->xDst = xDst;
|
||||
rect->yDst = yDst;
|
||||
rect->width = pGlyph->info.width;
|
||||
rect->height = pGlyph->info.height;
|
||||
|
||||
buffer->count++;
|
||||
|
||||
return ExaGlyphSuccess;
|
||||
}
|
||||
|
||||
#undef CACHE_X
|
||||
#undef CACHE_Y
|
||||
|
||||
static ExaGlyphCacheResult
|
||||
exaBufferGlyph(ScreenPtr pScreen,
|
||||
ExaGlyphBufferPtr buffer,
|
||||
GlyphPtr pGlyph,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pDst,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
unsigned int format = (GetGlyphPicture(pGlyph, pScreen))->format;
|
||||
int width = pGlyph->info.width;
|
||||
int height = pGlyph->info.height;
|
||||
ExaCompositeRectPtr rect;
|
||||
PicturePtr mask;
|
||||
int i;
|
||||
|
||||
if (buffer->count == GLYPH_BUFFER_SIZE)
|
||||
return ExaGlyphNeedFlush;
|
||||
|
||||
if (PICT_FORMAT_BPP(format) == 1)
|
||||
format = PICT_a8;
|
||||
|
||||
for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
|
||||
ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
|
||||
|
||||
if (format == cache->format &&
|
||||
width <= cache->glyphWidth && height <= cache->glyphHeight) {
|
||||
ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen,
|
||||
&pExaScr->
|
||||
glyphCaches
|
||||
[i],
|
||||
buffer,
|
||||
pGlyph,
|
||||
pSrc,
|
||||
pDst,
|
||||
xSrc, ySrc,
|
||||
xMask, yMask,
|
||||
xDst, yDst);
|
||||
|
||||
switch (result) {
|
||||
case ExaGlyphFail:
|
||||
break;
|
||||
case ExaGlyphSuccess:
|
||||
case ExaGlyphNeedFlush:
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Couldn't find the glyph in the cache, use the glyph picture directly */
|
||||
|
||||
mask = GetGlyphPicture(pGlyph, pScreen);
|
||||
if (buffer->mask && buffer->mask != mask)
|
||||
return ExaGlyphNeedFlush;
|
||||
|
||||
buffer->mask = mask;
|
||||
|
||||
rect = &buffer->rects[buffer->count];
|
||||
rect->xSrc = xSrc;
|
||||
rect->ySrc = ySrc;
|
||||
rect->xMask = xMask;
|
||||
rect->yMask = yMask;
|
||||
rect->xDst = xDst;
|
||||
rect->yDst = yDst;
|
||||
rect->width = width;
|
||||
rect->height = height;
|
||||
|
||||
buffer->count++;
|
||||
|
||||
return ExaGlyphSuccess;
|
||||
}
|
||||
|
||||
static void
|
||||
exaGlyphsToMask(PicturePtr pMask, ExaGlyphBufferPtr buffer)
|
||||
{
|
||||
exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask,
|
||||
buffer->count, buffer->rects);
|
||||
|
||||
buffer->count = 0;
|
||||
buffer->mask = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
exaGlyphsToDst(CARD8 op, PicturePtr pSrc, PicturePtr pDst, ExaGlyphBufferPtr buffer)
|
||||
{
|
||||
exaCompositeRects(op, pSrc, buffer->mask, pDst, buffer->count,
|
||||
buffer->rects);
|
||||
|
||||
buffer->count = 0;
|
||||
buffer->mask = NULL;
|
||||
}
|
||||
|
||||
/* Cut and paste from render/glyph.c - probably should export it instead */
|
||||
static void
|
||||
GlyphExtents(int nlist, GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents)
|
||||
{
|
||||
int x1, x2, y1, y2;
|
||||
int n;
|
||||
GlyphPtr glyph;
|
||||
int x, y;
|
||||
|
||||
x = 0;
|
||||
y = 0;
|
||||
extents->x1 = MAXSHORT;
|
||||
extents->x2 = MINSHORT;
|
||||
extents->y1 = MAXSHORT;
|
||||
extents->y2 = MINSHORT;
|
||||
while (nlist--) {
|
||||
x += list->xOff;
|
||||
y += list->yOff;
|
||||
n = list->len;
|
||||
list++;
|
||||
while (n--) {
|
||||
glyph = *glyphs++;
|
||||
x1 = x - glyph->info.x;
|
||||
if (x1 < MINSHORT)
|
||||
x1 = MINSHORT;
|
||||
y1 = y - glyph->info.y;
|
||||
if (y1 < MINSHORT)
|
||||
y1 = MINSHORT;
|
||||
x2 = x1 + glyph->info.width;
|
||||
if (x2 > MAXSHORT)
|
||||
x2 = MAXSHORT;
|
||||
y2 = y1 + glyph->info.height;
|
||||
if (y2 > MAXSHORT)
|
||||
y2 = MAXSHORT;
|
||||
if (x1 < extents->x1)
|
||||
extents->x1 = x1;
|
||||
if (x2 > extents->x2)
|
||||
extents->x2 = x2;
|
||||
if (y1 < extents->y1)
|
||||
extents->y1 = y1;
|
||||
if (y2 > extents->y2)
|
||||
extents->y2 = y2;
|
||||
x += glyph->info.xOff;
|
||||
y += glyph->info.yOff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
exaGlyphs(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pDst,
|
||||
PictFormatPtr maskFormat,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
|
||||
{
|
||||
PixmapPtr pMaskPixmap = 0;
|
||||
PicturePtr pMask = NULL;
|
||||
ScreenPtr pScreen = pDst->pDrawable->pScreen;
|
||||
int width = 0, height = 0;
|
||||
int x, y;
|
||||
int first_xOff = list->xOff, first_yOff = list->yOff;
|
||||
int n;
|
||||
GlyphPtr glyph;
|
||||
int error;
|
||||
BoxRec extents = { 0, 0, 0, 0 };
|
||||
CARD32 component_alpha;
|
||||
ExaGlyphBuffer buffer;
|
||||
|
||||
if (maskFormat) {
|
||||
ExaScreenPriv(pScreen);
|
||||
GCPtr pGC;
|
||||
xRectangle rect;
|
||||
|
||||
GlyphExtents(nlist, list, glyphs, &extents);
|
||||
|
||||
if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
|
||||
return;
|
||||
width = extents.x2 - extents.x1;
|
||||
height = extents.y2 - extents.y1;
|
||||
|
||||
if (maskFormat->depth == 1) {
|
||||
PictFormatPtr a8Format = PictureMatchFormat(pScreen, 8, PICT_a8);
|
||||
|
||||
if (a8Format)
|
||||
maskFormat = a8Format;
|
||||
}
|
||||
|
||||
pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
|
||||
maskFormat->depth,
|
||||
CREATE_PIXMAP_USAGE_SCRATCH);
|
||||
if (!pMaskPixmap)
|
||||
return;
|
||||
component_alpha = NeedsComponent(maskFormat->format);
|
||||
pMask = CreatePicture(0, &pMaskPixmap->drawable,
|
||||
maskFormat, CPComponentAlpha, &component_alpha,
|
||||
serverClient, &error);
|
||||
if (!pMask ||
|
||||
(!component_alpha && pExaScr->info->CheckComposite &&
|
||||
!(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask)))
|
||||
{
|
||||
PictFormatPtr argbFormat;
|
||||
|
||||
(*pScreen->DestroyPixmap) (pMaskPixmap);
|
||||
|
||||
if (!pMask)
|
||||
return;
|
||||
|
||||
/* The driver can't seem to composite to a8, let's try argb (but
|
||||
* without component-alpha) */
|
||||
FreePicture((void *) pMask, (XID) 0);
|
||||
|
||||
argbFormat = PictureMatchFormat(pScreen, 32, PICT_a8r8g8b8);
|
||||
|
||||
if (argbFormat)
|
||||
maskFormat = argbFormat;
|
||||
|
||||
pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
|
||||
maskFormat->depth,
|
||||
CREATE_PIXMAP_USAGE_SCRATCH);
|
||||
if (!pMaskPixmap)
|
||||
return;
|
||||
|
||||
pMask = CreatePicture(0, &pMaskPixmap->drawable, maskFormat, 0, 0,
|
||||
serverClient, &error);
|
||||
if (!pMask) {
|
||||
(*pScreen->DestroyPixmap) (pMaskPixmap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pGC = GetScratchGC(pMaskPixmap->drawable.depth, pScreen);
|
||||
ValidateGC(&pMaskPixmap->drawable, pGC);
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = width;
|
||||
rect.height = height;
|
||||
(*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
|
||||
FreeScratchGC(pGC);
|
||||
x = -extents.x1;
|
||||
y = -extents.y1;
|
||||
}
|
||||
else {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
buffer.count = 0;
|
||||
buffer.mask = NULL;
|
||||
while (nlist--) {
|
||||
x += list->xOff;
|
||||
y += list->yOff;
|
||||
n = list->len;
|
||||
while (n--) {
|
||||
glyph = *glyphs++;
|
||||
|
||||
if (glyph->info.width > 0 && glyph->info.height > 0) {
|
||||
/* pGlyph->info.{x,y} compensate for empty space in the glyph. */
|
||||
if (maskFormat) {
|
||||
if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
|
||||
0, 0, 0, 0, x - glyph->info.x,
|
||||
y - glyph->info.y) ==
|
||||
ExaGlyphNeedFlush) {
|
||||
exaGlyphsToMask(pMask, &buffer);
|
||||
exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
|
||||
0, 0, 0, 0, x - glyph->info.x,
|
||||
y - glyph->info.y);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
|
||||
xSrc + (x - glyph->info.x) - first_xOff,
|
||||
ySrc + (y - glyph->info.y) - first_yOff,
|
||||
0, 0, x - glyph->info.x,
|
||||
y - glyph->info.y)
|
||||
== ExaGlyphNeedFlush) {
|
||||
exaGlyphsToDst(op, pSrc, pDst, &buffer);
|
||||
exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
|
||||
xSrc + (x - glyph->info.x) - first_xOff,
|
||||
ySrc + (y - glyph->info.y) - first_yOff,
|
||||
0, 0, x - glyph->info.x,
|
||||
y - glyph->info.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x += glyph->info.xOff;
|
||||
y += glyph->info.yOff;
|
||||
}
|
||||
list++;
|
||||
}
|
||||
|
||||
if (buffer.count) {
|
||||
if (maskFormat)
|
||||
exaGlyphsToMask(pMask, &buffer);
|
||||
else
|
||||
exaGlyphsToDst(op, pSrc, pDst, &buffer);
|
||||
}
|
||||
|
||||
if (maskFormat) {
|
||||
x = extents.x1;
|
||||
y = extents.y1;
|
||||
CompositePicture(op,
|
||||
pSrc,
|
||||
pMask,
|
||||
pDst,
|
||||
xSrc + x - first_xOff,
|
||||
ySrc + y - first_yOff, 0, 0, x, y, width, height);
|
||||
FreePicture((void *) pMask, (XID) 0);
|
||||
(*pScreen->DestroyPixmap) (pMaskPixmap);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,761 @@
|
|||
/*
|
||||
* Copyright © 2006 Intel Corporation
|
||||
*
|
||||
* 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:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
* Michel Dänzer <michel@tungstengraphics.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "exa_priv.h"
|
||||
#include "exa.h"
|
||||
|
||||
#if DEBUG_MIGRATE
|
||||
#define DBG_MIGRATE(a) ErrorF a
|
||||
#else
|
||||
#define DBG_MIGRATE(a)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The fallback path for UTS/DFS failing is to just memcpy. exaCopyDirtyToSys
|
||||
* and exaCopyDirtyToFb both needed to do this loop.
|
||||
*/
|
||||
static void
|
||||
exaMemcpyBox(PixmapPtr pPixmap, BoxPtr pbox, CARD8 *src, int src_pitch,
|
||||
CARD8 *dst, int dst_pitch)
|
||||
{
|
||||
int i, cpp = pPixmap->drawable.bitsPerPixel / 8;
|
||||
int bytes = (pbox->x2 - pbox->x1) * cpp;
|
||||
|
||||
src += pbox->y1 * src_pitch + pbox->x1 * cpp;
|
||||
dst += pbox->y1 * dst_pitch + pbox->x1 * cpp;
|
||||
|
||||
for (i = pbox->y2 - pbox->y1; i; i--) {
|
||||
memcpy(dst, src, bytes);
|
||||
src += src_pitch;
|
||||
dst += dst_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if the pixmap is dirty (has been modified in its current
|
||||
* location compared to the other), or lacks a private for tracking
|
||||
* dirtiness.
|
||||
*/
|
||||
static Bool
|
||||
exaPixmapIsDirty(PixmapPtr pPix)
|
||||
{
|
||||
ExaPixmapPriv(pPix);
|
||||
|
||||
if (pExaPixmap == NULL)
|
||||
EXA_FatalErrorDebugWithRet(("EXA bug: exaPixmapIsDirty was called on a non-exa pixmap.\n"), TRUE);
|
||||
|
||||
if (!pExaPixmap->pDamage)
|
||||
return FALSE;
|
||||
|
||||
return RegionNotEmpty(DamageRegion(pExaPixmap->pDamage)) ||
|
||||
!RegionEqual(&pExaPixmap->validSys, &pExaPixmap->validFB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if the pixmap is either pinned in FB, or has a sufficient score
|
||||
* to be considered "should be in framebuffer". That's just anything that has
|
||||
* had more acceleration than fallbacks, or has no score yet.
|
||||
*
|
||||
* Only valid if using a migration scheme that tracks score.
|
||||
*/
|
||||
static Bool
|
||||
exaPixmapShouldBeInFB(PixmapPtr pPix)
|
||||
{
|
||||
ExaPixmapPriv(pPix);
|
||||
|
||||
if (exaPixmapIsPinned(pPix))
|
||||
return TRUE;
|
||||
|
||||
return pExaPixmap->score >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the pixmap is currently dirty, this copies at least the dirty area from
|
||||
* FB to system or vice versa. Both areas must be allocated.
|
||||
*/
|
||||
static void
|
||||
exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
|
||||
Bool (*transfer) (PixmapPtr pPix, int x, int y, int w, int h,
|
||||
char *sys, int sys_pitch), int fallback_index,
|
||||
void (*sync) (ScreenPtr pScreen))
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
RegionPtr damage = DamageRegion(pExaPixmap->pDamage);
|
||||
RegionRec CopyReg;
|
||||
Bool save_use_gpu_copy;
|
||||
int save_pitch;
|
||||
BoxPtr pBox;
|
||||
int nbox;
|
||||
Bool access_prepared = FALSE;
|
||||
Bool need_sync = FALSE;
|
||||
|
||||
/* Damaged bits are valid in current copy but invalid in other one */
|
||||
if (pExaPixmap->use_gpu_copy) {
|
||||
RegionUnion(&pExaPixmap->validFB, &pExaPixmap->validFB, damage);
|
||||
RegionSubtract(&pExaPixmap->validSys, &pExaPixmap->validSys, damage);
|
||||
}
|
||||
else {
|
||||
RegionUnion(&pExaPixmap->validSys, &pExaPixmap->validSys, damage);
|
||||
RegionSubtract(&pExaPixmap->validFB, &pExaPixmap->validFB, damage);
|
||||
}
|
||||
|
||||
RegionEmpty(damage);
|
||||
|
||||
/* Copy bits valid in source but not in destination */
|
||||
RegionNull(&CopyReg);
|
||||
RegionSubtract(&CopyReg, pValidSrc, pValidDst);
|
||||
|
||||
if (migrate->as_dst) {
|
||||
ExaScreenPriv(pPixmap->drawable.pScreen);
|
||||
|
||||
/* XXX: The pending damage region will be marked as damaged after the
|
||||
* operation, so it should serve as an upper bound for the region that
|
||||
* needs to be synchronized for the operation. Unfortunately, this
|
||||
* causes corruption in some cases, e.g. when starting compiz. See
|
||||
* https://bugs.freedesktop.org/show_bug.cgi?id=12916 .
|
||||
*/
|
||||
if (pExaScr->optimize_migration) {
|
||||
RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
|
||||
|
||||
#if DEBUG_MIGRATE
|
||||
if (RegionNil(pending_damage)) {
|
||||
static Bool firsttime = TRUE;
|
||||
|
||||
if (firsttime) {
|
||||
ErrorF("%s: Pending damage region empty!\n", __func__);
|
||||
firsttime = FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Try to prevent destination valid region from growing too many
|
||||
* rects by filling it up to the extents of the union of the
|
||||
* destination valid region and the pending damage region.
|
||||
*/
|
||||
if (RegionNumRects(pValidDst) > 10) {
|
||||
BoxRec box;
|
||||
BoxPtr pValidExt, pDamageExt;
|
||||
RegionRec closure;
|
||||
|
||||
pValidExt = RegionExtents(pValidDst);
|
||||
pDamageExt = RegionExtents(pending_damage);
|
||||
|
||||
box.x1 = min(pValidExt->x1, pDamageExt->x1);
|
||||
box.y1 = min(pValidExt->y1, pDamageExt->y1);
|
||||
box.x2 = max(pValidExt->x2, pDamageExt->x2);
|
||||
box.y2 = max(pValidExt->y2, pDamageExt->y2);
|
||||
|
||||
RegionInit(&closure, &box, 0);
|
||||
RegionIntersect(&CopyReg, &CopyReg, &closure);
|
||||
}
|
||||
else
|
||||
RegionIntersect(&CopyReg, &CopyReg, pending_damage);
|
||||
}
|
||||
|
||||
/* The caller may provide a region to be subtracted from the calculated
|
||||
* dirty region. This is to avoid migration of bits that don't
|
||||
* contribute to the result of the operation.
|
||||
*/
|
||||
if (migrate->pReg)
|
||||
RegionSubtract(&CopyReg, &CopyReg, migrate->pReg);
|
||||
}
|
||||
else {
|
||||
/* The caller may restrict the region to be migrated for source pixmaps
|
||||
* to what's relevant for the operation.
|
||||
*/
|
||||
if (migrate->pReg)
|
||||
RegionIntersect(&CopyReg, &CopyReg, migrate->pReg);
|
||||
}
|
||||
|
||||
pBox = RegionRects(&CopyReg);
|
||||
nbox = RegionNumRects(&CopyReg);
|
||||
|
||||
save_use_gpu_copy = pExaPixmap->use_gpu_copy;
|
||||
save_pitch = pPixmap->devKind;
|
||||
pExaPixmap->use_gpu_copy = TRUE;
|
||||
pPixmap->devKind = pExaPixmap->fb_pitch;
|
||||
|
||||
while (nbox--) {
|
||||
pBox->x1 = max(pBox->x1, 0);
|
||||
pBox->y1 = max(pBox->y1, 0);
|
||||
pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
|
||||
pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
|
||||
|
||||
if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
|
||||
continue;
|
||||
|
||||
if (!transfer || !transfer(pPixmap,
|
||||
pBox->x1, pBox->y1,
|
||||
pBox->x2 - pBox->x1,
|
||||
pBox->y2 - pBox->y1,
|
||||
(char *) (pExaPixmap->sys_ptr
|
||||
+ pBox->y1 * pExaPixmap->sys_pitch
|
||||
+
|
||||
pBox->x1 *
|
||||
pPixmap->drawable.bitsPerPixel /
|
||||
8), pExaPixmap->sys_pitch)) {
|
||||
if (!access_prepared) {
|
||||
ExaDoPrepareAccess(pPixmap, fallback_index);
|
||||
access_prepared = TRUE;
|
||||
}
|
||||
if (fallback_index == EXA_PREPARE_DEST) {
|
||||
exaMemcpyBox(pPixmap, pBox,
|
||||
pExaPixmap->sys_ptr, pExaPixmap->sys_pitch,
|
||||
pPixmap->devPrivate.ptr, pPixmap->devKind);
|
||||
}
|
||||
else {
|
||||
exaMemcpyBox(pPixmap, pBox,
|
||||
pPixmap->devPrivate.ptr, pPixmap->devKind,
|
||||
pExaPixmap->sys_ptr, pExaPixmap->sys_pitch);
|
||||
}
|
||||
}
|
||||
else
|
||||
need_sync = TRUE;
|
||||
|
||||
pBox++;
|
||||
}
|
||||
|
||||
pExaPixmap->use_gpu_copy = save_use_gpu_copy;
|
||||
pPixmap->devKind = save_pitch;
|
||||
|
||||
/* Try to prevent source valid region from growing too many rects by
|
||||
* removing parts of it which are also in the destination valid region.
|
||||
* Removing anything beyond that would lead to data loss.
|
||||
*/
|
||||
if (RegionNumRects(pValidSrc) > 20)
|
||||
RegionSubtract(pValidSrc, pValidSrc, pValidDst);
|
||||
|
||||
/* The copied bits are now valid in destination */
|
||||
RegionUnion(pValidDst, pValidDst, &CopyReg);
|
||||
|
||||
RegionUninit(&CopyReg);
|
||||
|
||||
if (access_prepared)
|
||||
exaFinishAccess(&pPixmap->drawable, fallback_index);
|
||||
else if (need_sync && sync)
|
||||
sync(pPixmap->drawable.pScreen);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the pixmap is currently dirty, this copies at least the dirty area from
|
||||
* the framebuffer memory copy to the system memory copy. Both areas must be
|
||||
* allocated.
|
||||
*/
|
||||
void
|
||||
exaCopyDirtyToSys(ExaMigrationPtr migrate)
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
|
||||
ExaScreenPriv(pPixmap->drawable.pScreen);
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
exaCopyDirty(migrate, &pExaPixmap->validSys, &pExaPixmap->validFB,
|
||||
pExaScr->info->DownloadFromScreen, EXA_PREPARE_SRC,
|
||||
exaWaitSync);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the pixmap is currently dirty, this copies at least the dirty area from
|
||||
* the system memory copy to the framebuffer memory copy. Both areas must be
|
||||
* allocated.
|
||||
*/
|
||||
void
|
||||
exaCopyDirtyToFb(ExaMigrationPtr migrate)
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
|
||||
ExaScreenPriv(pPixmap->drawable.pScreen);
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
exaCopyDirty(migrate, &pExaPixmap->validFB, &pExaPixmap->validSys,
|
||||
pExaScr->info->UploadToScreen, EXA_PREPARE_DEST, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a framebuffer copy of the pixmap if necessary, and then copies
|
||||
* any necessary pixmap data into the framebuffer copy and points the pixmap at
|
||||
* it.
|
||||
*
|
||||
* Note that when first allocated, a pixmap will have FALSE dirty flag.
|
||||
* This is intentional because pixmap data starts out undefined. So if we move
|
||||
* it in due to the first operation against it being accelerated, it will have
|
||||
* undefined framebuffer contents that we didn't have to upload. If we do
|
||||
* moveouts (and moveins) after the first movein, then we will only have to copy
|
||||
* back and forth if the pixmap was written to after the last synchronization of
|
||||
* the two copies. Then, at exaPixmapSave (when the framebuffer copy goes away)
|
||||
* we mark the pixmap dirty, so that the next exaMoveInPixmap will actually move
|
||||
* all the data, since it's almost surely all valid now.
|
||||
*/
|
||||
static void
|
||||
exaDoMoveInPixmap(ExaMigrationPtr migrate)
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
/* If we're VT-switched away, no touching card memory allowed. */
|
||||
if (pExaScr->swappedOut)
|
||||
return;
|
||||
|
||||
/* If we're not allowed to move, then fail. */
|
||||
if (exaPixmapIsPinned(pPixmap))
|
||||
return;
|
||||
|
||||
/* Don't migrate in pixmaps which are less than 8bpp. This avoids a lot of
|
||||
* fragility in EXA, and <8bpp is probably not used enough any more to care
|
||||
* (at least, not in acceleratd paths).
|
||||
*/
|
||||
if (pPixmap->drawable.bitsPerPixel < 8)
|
||||
return;
|
||||
|
||||
if (pExaPixmap->accel_blocked)
|
||||
return;
|
||||
|
||||
if (pExaPixmap->area == NULL) {
|
||||
pExaPixmap->area =
|
||||
exaOffscreenAlloc(pScreen, pExaPixmap->fb_size,
|
||||
pExaScr->info->pixmapOffsetAlign, FALSE,
|
||||
exaPixmapSave, (void *) pPixmap);
|
||||
if (pExaPixmap->area == NULL)
|
||||
return;
|
||||
|
||||
pExaPixmap->fb_ptr = (CARD8 *) pExaScr->info->memoryBase +
|
||||
pExaPixmap->area->offset;
|
||||
}
|
||||
|
||||
exaCopyDirtyToFb(migrate);
|
||||
|
||||
if (exaPixmapHasGpuCopy(pPixmap))
|
||||
return;
|
||||
|
||||
DBG_MIGRATE(("-> %p (0x%x) (%dx%d) (%c)\n", pPixmap,
|
||||
(ExaGetPixmapPriv(pPixmap)->area ?
|
||||
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
|
||||
pPixmap->drawable.width,
|
||||
pPixmap->drawable.height,
|
||||
exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
|
||||
|
||||
pExaPixmap->use_gpu_copy = TRUE;
|
||||
|
||||
pPixmap->devKind = pExaPixmap->fb_pitch;
|
||||
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
|
||||
}
|
||||
|
||||
void
|
||||
exaMoveInPixmap_classic(PixmapPtr pPixmap)
|
||||
{
|
||||
static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE,
|
||||
.pReg = NULL
|
||||
};
|
||||
|
||||
migrate.pPix = pPixmap;
|
||||
exaDoMoveInPixmap(&migrate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches the current active location of the pixmap to system memory, copying
|
||||
* updated data out if necessary.
|
||||
*/
|
||||
static void
|
||||
exaDoMoveOutPixmap(ExaMigrationPtr migrate)
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
|
||||
return;
|
||||
|
||||
exaCopyDirtyToSys(migrate);
|
||||
|
||||
if (exaPixmapHasGpuCopy(pPixmap)) {
|
||||
|
||||
DBG_MIGRATE(("<- %p (%p) (%dx%d) (%c)\n", pPixmap,
|
||||
(void *) (ExaGetPixmapPriv(pPixmap)->area ?
|
||||
ExaGetPixmapPriv(pPixmap)->area->offset : 0),
|
||||
pPixmap->drawable.width,
|
||||
pPixmap->drawable.height,
|
||||
exaPixmapIsDirty(pPixmap) ? 'd' : 'c'));
|
||||
|
||||
pExaPixmap->use_gpu_copy = FALSE;
|
||||
|
||||
pPixmap->devKind = pExaPixmap->sys_pitch;
|
||||
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
exaMoveOutPixmap_classic(PixmapPtr pPixmap)
|
||||
{
|
||||
static ExaMigrationRec migrate = {.as_dst = FALSE,.as_src = TRUE,
|
||||
.pReg = NULL
|
||||
};
|
||||
|
||||
migrate.pPix = pPixmap;
|
||||
exaDoMoveOutPixmap(&migrate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies out important pixmap data and removes references to framebuffer area.
|
||||
* Called when the memory manager decides it's time to kick the pixmap out of
|
||||
* framebuffer entirely.
|
||||
*/
|
||||
void
|
||||
exaPixmapSave(ScreenPtr pScreen, ExaOffscreenArea * area)
|
||||
{
|
||||
PixmapPtr pPixmap = area->privData;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
exaMoveOutPixmap(pPixmap);
|
||||
|
||||
pExaPixmap->fb_ptr = NULL;
|
||||
pExaPixmap->area = NULL;
|
||||
|
||||
/* Mark all FB bits as invalid, so all valid system bits get copied to FB
|
||||
* next time */
|
||||
RegionEmpty(&pExaPixmap->validFB);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the "greedy" migration scheme, pushes the pixmap toward being located in
|
||||
* framebuffer memory.
|
||||
*/
|
||||
static void
|
||||
exaMigrateTowardFb(ExaMigrationPtr migrate)
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED) {
|
||||
DBG_MIGRATE(("UseScreen: not migrating pinned pixmap %p\n",
|
||||
(void *) pPixmap));
|
||||
return;
|
||||
}
|
||||
|
||||
DBG_MIGRATE(("UseScreen %p score %d\n",
|
||||
(void *) pPixmap, pExaPixmap->score));
|
||||
|
||||
if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT) {
|
||||
exaDoMoveInPixmap(migrate);
|
||||
pExaPixmap->score = 0;
|
||||
}
|
||||
|
||||
if (pExaPixmap->score < EXA_PIXMAP_SCORE_MAX)
|
||||
pExaPixmap->score++;
|
||||
|
||||
if (pExaPixmap->score >= EXA_PIXMAP_SCORE_MOVE_IN &&
|
||||
!exaPixmapHasGpuCopy(pPixmap)) {
|
||||
exaDoMoveInPixmap(migrate);
|
||||
}
|
||||
|
||||
if (exaPixmapHasGpuCopy(pPixmap)) {
|
||||
exaCopyDirtyToFb(migrate);
|
||||
ExaOffscreenMarkUsed(pPixmap);
|
||||
}
|
||||
else
|
||||
exaCopyDirtyToSys(migrate);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the "greedy" migration scheme, pushes the pixmap toward being located in
|
||||
* system memory.
|
||||
*/
|
||||
static void
|
||||
exaMigrateTowardSys(ExaMigrationPtr migrate)
|
||||
{
|
||||
PixmapPtr pPixmap = migrate->pPix;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
DBG_MIGRATE(("UseMem: %p score %d\n", (void *) pPixmap,
|
||||
pExaPixmap->score));
|
||||
|
||||
if (pExaPixmap->score == EXA_PIXMAP_SCORE_PINNED)
|
||||
return;
|
||||
|
||||
if (pExaPixmap->score == EXA_PIXMAP_SCORE_INIT)
|
||||
pExaPixmap->score = 0;
|
||||
|
||||
if (pExaPixmap->score > EXA_PIXMAP_SCORE_MIN)
|
||||
pExaPixmap->score--;
|
||||
|
||||
if (pExaPixmap->score <= EXA_PIXMAP_SCORE_MOVE_OUT && pExaPixmap->area)
|
||||
exaDoMoveOutPixmap(migrate);
|
||||
|
||||
if (exaPixmapHasGpuCopy(pPixmap)) {
|
||||
exaCopyDirtyToFb(migrate);
|
||||
ExaOffscreenMarkUsed(pPixmap);
|
||||
}
|
||||
else
|
||||
exaCopyDirtyToSys(migrate);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the pixmap has both a framebuffer and system memory copy, this function
|
||||
* asserts that both of them are the same.
|
||||
*/
|
||||
static Bool
|
||||
exaAssertNotDirty(PixmapPtr pPixmap)
|
||||
{
|
||||
ExaPixmapPriv(pPixmap);
|
||||
CARD8 *dst, *src;
|
||||
RegionRec ValidReg;
|
||||
int dst_pitch, src_pitch, cpp, y, nbox, save_pitch;
|
||||
BoxPtr pBox;
|
||||
Bool ret = TRUE, save_use_gpu_copy;
|
||||
|
||||
if (exaPixmapIsPinned(pPixmap) || pExaPixmap->area == NULL)
|
||||
return ret;
|
||||
|
||||
RegionNull(&ValidReg);
|
||||
RegionIntersect(&ValidReg, &pExaPixmap->validFB, &pExaPixmap->validSys);
|
||||
nbox = RegionNumRects(&ValidReg);
|
||||
|
||||
if (!nbox)
|
||||
goto out;
|
||||
|
||||
pBox = RegionRects(&ValidReg);
|
||||
|
||||
dst_pitch = pExaPixmap->sys_pitch;
|
||||
src_pitch = pExaPixmap->fb_pitch;
|
||||
cpp = pPixmap->drawable.bitsPerPixel / 8;
|
||||
|
||||
save_use_gpu_copy = pExaPixmap->use_gpu_copy;
|
||||
save_pitch = pPixmap->devKind;
|
||||
pExaPixmap->use_gpu_copy = TRUE;
|
||||
pPixmap->devKind = pExaPixmap->fb_pitch;
|
||||
|
||||
if (!ExaDoPrepareAccess(pPixmap, EXA_PREPARE_SRC))
|
||||
goto skip;
|
||||
|
||||
while (nbox--) {
|
||||
int rowbytes;
|
||||
|
||||
pBox->x1 = max(pBox->x1, 0);
|
||||
pBox->y1 = max(pBox->y1, 0);
|
||||
pBox->x2 = min(pBox->x2, pPixmap->drawable.width);
|
||||
pBox->y2 = min(pBox->y2, pPixmap->drawable.height);
|
||||
|
||||
if (pBox->x1 >= pBox->x2 || pBox->y1 >= pBox->y2)
|
||||
continue;
|
||||
|
||||
rowbytes = (pBox->x2 - pBox->x1) * cpp;
|
||||
src =
|
||||
(CARD8 *) pPixmap->devPrivate.ptr + pBox->y1 * src_pitch +
|
||||
pBox->x1 * cpp;
|
||||
dst = pExaPixmap->sys_ptr + pBox->y1 * dst_pitch + pBox->x1 * cpp;
|
||||
|
||||
for (y = pBox->y1; y < pBox->y2;
|
||||
y++, src += src_pitch, dst += dst_pitch) {
|
||||
if (memcmp(dst, src, rowbytes) != 0) {
|
||||
ret = FALSE;
|
||||
exaPixmapDirty(pPixmap, pBox->x1, pBox->y1, pBox->x2, pBox->y2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skip:
|
||||
exaFinishAccess(&pPixmap->drawable, EXA_PREPARE_SRC);
|
||||
|
||||
pExaPixmap->use_gpu_copy = save_use_gpu_copy;
|
||||
pPixmap->devKind = save_pitch;
|
||||
|
||||
out:
|
||||
RegionUninit(&ValidReg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs migration of the pixmaps according to the operation information
|
||||
* provided in pixmaps and can_accel and the migration scheme chosen in the
|
||||
* config file.
|
||||
*/
|
||||
void
|
||||
exaDoMigration_classic(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
|
||||
{
|
||||
ScreenPtr pScreen = pixmaps[0].pPix->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
int i, j;
|
||||
|
||||
/* If this debugging flag is set, check each pixmap for whether it is marked
|
||||
* as clean, and if so, actually check if that's the case. This should help
|
||||
* catch issues with failing to mark a drawable as dirty. While it will
|
||||
* catch them late (after the operation happened), it at least explains what
|
||||
* went wrong, and instrumenting the code to find what operation happened
|
||||
* to the pixmap last shouldn't be hard.
|
||||
*/
|
||||
if (pExaScr->checkDirtyCorrectness) {
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (!exaPixmapIsDirty(pixmaps[i].pPix) &&
|
||||
!exaAssertNotDirty(pixmaps[i].pPix))
|
||||
ErrorF("%s: Pixmap %d dirty but not marked as such!\n",
|
||||
__func__, i);
|
||||
}
|
||||
}
|
||||
/* If anything is pinned in system memory, we won't be able to
|
||||
* accelerate.
|
||||
*/
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (exaPixmapIsPinned(pixmaps[i].pPix) &&
|
||||
!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
|
||||
EXA_FALLBACK(("Pixmap %p (%dx%d) pinned in sys\n", pixmaps[i].pPix,
|
||||
pixmaps[i].pPix->drawable.width,
|
||||
pixmaps[i].pPix->drawable.height));
|
||||
can_accel = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pExaScr->migration == ExaMigrationSmart) {
|
||||
/* If we've got something as a destination that we shouldn't cause to
|
||||
* become newly dirtied, take the unaccelerated route.
|
||||
*/
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (pixmaps[i].as_dst && !exaPixmapShouldBeInFB(pixmaps[i].pPix) &&
|
||||
!exaPixmapIsDirty(pixmaps[i].pPix)) {
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (!exaPixmapIsDirty(pixmaps[i].pPix))
|
||||
exaDoMoveOutPixmap(pixmaps + i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we aren't going to accelerate, then we migrate everybody toward
|
||||
* system memory, and kick out if it's free.
|
||||
*/
|
||||
if (!can_accel) {
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
exaMigrateTowardSys(pixmaps + i);
|
||||
if (!exaPixmapIsDirty(pixmaps[i].pPix))
|
||||
exaDoMoveOutPixmap(pixmaps + i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Finally, the acceleration path. Move them all in. */
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
exaMigrateTowardFb(pixmaps + i);
|
||||
exaDoMoveInPixmap(pixmaps + i);
|
||||
}
|
||||
}
|
||||
else if (pExaScr->migration == ExaMigrationGreedy) {
|
||||
/* If we can't accelerate, either because the driver can't or because one of
|
||||
* the pixmaps is pinned in system memory, then we migrate everybody toward
|
||||
* system memory.
|
||||
*
|
||||
* We also migrate toward system if all pixmaps involved are currently in
|
||||
* system memory -- this can mitigate thrashing when there are significantly
|
||||
* more pixmaps active than would fit in memory.
|
||||
*
|
||||
* If not, then we migrate toward FB so that hopefully acceleration can
|
||||
* happen.
|
||||
*/
|
||||
if (!can_accel) {
|
||||
for (i = 0; i < npixmaps; i++)
|
||||
exaMigrateTowardSys(pixmaps + i);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
|
||||
/* Found one in FB, so move all to FB. */
|
||||
for (j = 0; j < npixmaps; j++)
|
||||
exaMigrateTowardFb(pixmaps + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Nobody's in FB, so move all away from FB. */
|
||||
for (i = 0; i < npixmaps; i++)
|
||||
exaMigrateTowardSys(pixmaps + i);
|
||||
}
|
||||
else if (pExaScr->migration == ExaMigrationAlways) {
|
||||
/* Always move the pixmaps out if we can't accelerate. If we can
|
||||
* accelerate, try to move them all in. If that fails, then move them
|
||||
* back out.
|
||||
*/
|
||||
if (!can_accel) {
|
||||
for (i = 0; i < npixmaps; i++)
|
||||
exaDoMoveOutPixmap(pixmaps + i);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now, try to move them all into FB */
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
exaDoMoveInPixmap(pixmaps + i);
|
||||
}
|
||||
|
||||
/* If we couldn't fit everything in, abort */
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Yay, everything has a gpu copy, mark memory as used */
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
ExaOffscreenMarkUsed(pixmaps[i].pPix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg)
|
||||
{
|
||||
ExaMigrationRec pixmaps[1];
|
||||
|
||||
if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
|
||||
pixmaps[0].as_dst = TRUE;
|
||||
pixmaps[0].as_src = FALSE;
|
||||
}
|
||||
else {
|
||||
pixmaps[0].as_dst = FALSE;
|
||||
pixmaps[0].as_src = TRUE;
|
||||
}
|
||||
pixmaps[0].pPix = pPixmap;
|
||||
pixmaps[0].pReg = pReg;
|
||||
|
||||
exaDoMigration(pixmaps, 1, FALSE);
|
||||
|
||||
(void) ExaDoPrepareAccess(pPixmap, index);
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* Copyright © 2009 Maarten Maathuis
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "exa_priv.h"
|
||||
#include "exa.h"
|
||||
|
||||
void
|
||||
exaCreateDriverPixmap_mixed(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaPixmapPriv(pPixmap);
|
||||
int w = pPixmap->drawable.width, h = pPixmap->drawable.height;
|
||||
int depth = pPixmap->drawable.depth, bpp = pPixmap->drawable.bitsPerPixel;
|
||||
int usage_hint = pPixmap->usage_hint;
|
||||
int paddedWidth = pExaPixmap->sys_pitch;
|
||||
|
||||
/* Already done. */
|
||||
if (pExaPixmap->driverPriv)
|
||||
return;
|
||||
|
||||
if (exaPixmapIsPinned(pPixmap))
|
||||
return;
|
||||
|
||||
/* Can't accel 1/4 bpp. */
|
||||
if (pExaPixmap->accel_blocked || bpp < 8)
|
||||
return;
|
||||
|
||||
if (pExaScr->info->CreatePixmap2) {
|
||||
int new_pitch = 0;
|
||||
|
||||
pExaPixmap->driverPriv =
|
||||
pExaScr->info->CreatePixmap2(pScreen, w, h, depth, usage_hint, bpp,
|
||||
&new_pitch);
|
||||
paddedWidth = pExaPixmap->fb_pitch = new_pitch;
|
||||
}
|
||||
else {
|
||||
if (paddedWidth < pExaPixmap->fb_pitch)
|
||||
paddedWidth = pExaPixmap->fb_pitch;
|
||||
pExaPixmap->driverPriv =
|
||||
pExaScr->info->CreatePixmap(pScreen, paddedWidth * h, 0);
|
||||
}
|
||||
|
||||
if (!pExaPixmap->driverPriv)
|
||||
return;
|
||||
|
||||
(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* If anything is pinned in system memory, we won't be able to
|
||||
* accelerate.
|
||||
*/
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
if (exaPixmapIsPinned(pixmaps[i].pPix) &&
|
||||
!exaPixmapHasGpuCopy(pixmaps[i].pPix)) {
|
||||
can_accel = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We can do nothing. */
|
||||
if (!can_accel)
|
||||
return;
|
||||
|
||||
for (i = 0; i < npixmaps; i++) {
|
||||
PixmapPtr pPixmap = pixmaps[i].pPix;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
if (!pExaPixmap->driverPriv)
|
||||
exaCreateDriverPixmap_mixed(pPixmap);
|
||||
|
||||
if (pExaPixmap->pDamage && exaPixmapHasGpuCopy(pPixmap)) {
|
||||
ExaScreenPriv(pPixmap->drawable.pScreen);
|
||||
|
||||
/* This pitch is needed for proper acceleration. For some reason
|
||||
* there are pixmaps without pDamage and a bad fb_pitch value.
|
||||
* So setting devKind when only exaPixmapHasGpuCopy() is true
|
||||
* causes corruption. Pixmaps without pDamage are not migrated
|
||||
* and should have a valid devKind at all times, so that's why this
|
||||
* isn't causing problems. Pixmaps have their gpu pitch set the
|
||||
* first time in the MPH call from exaCreateDriverPixmap_mixed().
|
||||
*/
|
||||
pPixmap->devKind = pExaPixmap->fb_pitch;
|
||||
exaCopyDirtyToFb(pixmaps + i);
|
||||
|
||||
if (pExaScr->deferred_mixed_pixmap == pPixmap &&
|
||||
!pixmaps[i].as_dst && !pixmaps[i].pReg)
|
||||
pExaScr->deferred_mixed_pixmap = NULL;
|
||||
}
|
||||
|
||||
pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
exaMoveInPixmap_mixed(PixmapPtr pPixmap)
|
||||
{
|
||||
ExaMigrationRec pixmaps[1];
|
||||
|
||||
pixmaps[0].as_dst = FALSE;
|
||||
pixmaps[0].as_src = TRUE;
|
||||
pixmaps[0].pPix = pPixmap;
|
||||
pixmaps[0].pReg = NULL;
|
||||
|
||||
exaDoMigration(pixmaps, 1, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure)
|
||||
{
|
||||
PixmapPtr pPixmap = closure;
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
/* Move back results of software rendering on system memory copy of mixed driver
|
||||
* pixmap (see exaPrepareAccessReg_mixed).
|
||||
*
|
||||
* Defer moving the destination back into the driver pixmap, to try and save
|
||||
* overhead on multiple subsequent software fallbacks.
|
||||
*/
|
||||
if (!pExaPixmap->use_gpu_copy && exaPixmapHasGpuCopy(pPixmap)) {
|
||||
ExaScreenPriv(pPixmap->drawable.pScreen);
|
||||
|
||||
if (pExaScr->deferred_mixed_pixmap &&
|
||||
pExaScr->deferred_mixed_pixmap != pPixmap)
|
||||
exaMoveInPixmap_mixed(pExaScr->deferred_mixed_pixmap);
|
||||
pExaScr->deferred_mixed_pixmap = pPixmap;
|
||||
}
|
||||
}
|
||||
|
||||
/* With mixed pixmaps, if we fail to get direct access to the driver pixmap, we
|
||||
* use the DownloadFromScreen hook to retrieve contents to a copy in system
|
||||
* memory, perform software rendering on that and move back the results with the
|
||||
* UploadToScreen hook (see exaDamageReport_mixed).
|
||||
*/
|
||||
void
|
||||
exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg)
|
||||
{
|
||||
ExaPixmapPriv(pPixmap);
|
||||
Bool has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
|
||||
Bool success;
|
||||
|
||||
success = ExaDoPrepareAccess(pPixmap, index);
|
||||
|
||||
if (success && has_gpu_copy && pExaPixmap->pDamage) {
|
||||
/* You cannot do accelerated operations while a buffer is mapped. */
|
||||
exaFinishAccess(&pPixmap->drawable, index);
|
||||
/* Update the gpu view of both deferred destination pixmaps and of
|
||||
* source pixmaps that were migrated with a bounding region.
|
||||
*/
|
||||
exaMoveInPixmap_mixed(pPixmap);
|
||||
success = ExaDoPrepareAccess(pPixmap, index);
|
||||
|
||||
if (success) {
|
||||
/* We have a gpu pixmap that can be accessed, we don't need the cpu
|
||||
* copy anymore. Drivers that prefer DFS, should fail prepare
|
||||
* access.
|
||||
*/
|
||||
DamageDestroy(pExaPixmap->pDamage);
|
||||
pExaPixmap->pDamage = NULL;
|
||||
|
||||
free(pExaPixmap->sys_ptr);
|
||||
pExaPixmap->sys_ptr = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
ExaMigrationRec pixmaps[1];
|
||||
|
||||
/* Do we need to allocate our system buffer? */
|
||||
if (!pExaPixmap->sys_ptr) {
|
||||
pExaPixmap->sys_ptr = xallocarray(pExaPixmap->sys_pitch,
|
||||
pPixmap->drawable.height);
|
||||
if (!pExaPixmap->sys_ptr)
|
||||
FatalError("EXA: malloc failed for size %d bytes\n",
|
||||
pExaPixmap->sys_pitch * pPixmap->drawable.height);
|
||||
}
|
||||
|
||||
if (index == EXA_PREPARE_DEST || index == EXA_PREPARE_AUX_DEST) {
|
||||
pixmaps[0].as_dst = TRUE;
|
||||
pixmaps[0].as_src = FALSE;
|
||||
}
|
||||
else {
|
||||
pixmaps[0].as_dst = FALSE;
|
||||
pixmaps[0].as_src = TRUE;
|
||||
}
|
||||
pixmaps[0].pPix = pPixmap;
|
||||
pixmaps[0].pReg = pReg;
|
||||
|
||||
if (!pExaPixmap->pDamage &&
|
||||
(has_gpu_copy || !exaPixmapIsPinned(pPixmap))) {
|
||||
Bool as_dst = pixmaps[0].as_dst;
|
||||
|
||||
/* Set up damage tracking */
|
||||
pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
|
||||
DamageReportNonEmpty, TRUE,
|
||||
pPixmap->drawable.pScreen,
|
||||
pPixmap);
|
||||
|
||||
if (pExaPixmap->pDamage) {
|
||||
DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
|
||||
/* This ensures that pending damage reflects the current
|
||||
* operation. This is used by exa to optimize migration.
|
||||
*/
|
||||
DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
|
||||
}
|
||||
|
||||
if (has_gpu_copy) {
|
||||
exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
|
||||
pPixmap->drawable.height);
|
||||
|
||||
/* We don't know which region of the destination will be damaged,
|
||||
* have to assume all of it
|
||||
*/
|
||||
if (as_dst) {
|
||||
pixmaps[0].as_dst = FALSE;
|
||||
pixmaps[0].as_src = TRUE;
|
||||
pixmaps[0].pReg = NULL;
|
||||
}
|
||||
exaCopyDirtyToSys(pixmaps);
|
||||
}
|
||||
|
||||
if (as_dst)
|
||||
exaPixmapDirty(pPixmap, 0, 0, pPixmap->drawable.width,
|
||||
pPixmap->drawable.height);
|
||||
}
|
||||
else if (has_gpu_copy)
|
||||
exaCopyDirtyToSys(pixmaps);
|
||||
|
||||
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
|
||||
pPixmap->devKind = pExaPixmap->sys_pitch;
|
||||
pExaPixmap->use_gpu_copy = FALSE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,330 @@
|
|||
/*
|
||||
* Copyright © 2009 Maarten Maathuis
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "exa_priv.h"
|
||||
#include "exa.h"
|
||||
|
||||
/* This file holds the driver allocated pixmaps + better initial placement code.
|
||||
*/
|
||||
|
||||
static _X_INLINE void *
|
||||
ExaGetPixmapAddress(PixmapPtr p)
|
||||
{
|
||||
ExaPixmapPriv(p);
|
||||
|
||||
return pExaPixmap->sys_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* exaCreatePixmap() creates a new pixmap.
|
||||
*/
|
||||
PixmapPtr
|
||||
exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
|
||||
unsigned usage_hint)
|
||||
{
|
||||
PixmapPtr pPixmap;
|
||||
ExaPixmapPrivPtr pExaPixmap;
|
||||
int bpp;
|
||||
size_t paddedWidth;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
if (w > 32767 || h > 32767)
|
||||
return NullPixmap;
|
||||
|
||||
swap(pExaScr, pScreen, CreatePixmap);
|
||||
pPixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, usage_hint);
|
||||
swap(pExaScr, pScreen, CreatePixmap);
|
||||
|
||||
if (!pPixmap)
|
||||
return NULL;
|
||||
|
||||
pExaPixmap = ExaGetPixmapPriv(pPixmap);
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
|
||||
bpp = pPixmap->drawable.bitsPerPixel;
|
||||
|
||||
paddedWidth = ((w * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
|
||||
if (paddedWidth / 4 > 32767 || h > 32767)
|
||||
return NullPixmap;
|
||||
|
||||
/* We will allocate the system pixmap later if needed. */
|
||||
pPixmap->devPrivate.ptr = NULL;
|
||||
pExaPixmap->sys_ptr = NULL;
|
||||
pExaPixmap->sys_pitch = paddedWidth;
|
||||
|
||||
pExaPixmap->area = NULL;
|
||||
pExaPixmap->fb_ptr = NULL;
|
||||
pExaPixmap->pDamage = NULL;
|
||||
|
||||
exaSetFbPitch(pExaScr, pExaPixmap, w, h, bpp);
|
||||
exaSetAccelBlock(pExaScr, pExaPixmap, w, h, bpp);
|
||||
|
||||
(*pScreen->ModifyPixmapHeader) (pPixmap, w, h, 0, 0, paddedWidth, NULL);
|
||||
|
||||
/* A scratch pixmap will become a driver pixmap right away. */
|
||||
if (!w || !h) {
|
||||
exaCreateDriverPixmap_mixed(pPixmap);
|
||||
pExaPixmap->use_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
|
||||
}
|
||||
else {
|
||||
pExaPixmap->use_gpu_copy = FALSE;
|
||||
|
||||
if (w == 1 && h == 1) {
|
||||
pExaPixmap->sys_ptr = malloc(paddedWidth);
|
||||
|
||||
/* Set up damage tracking */
|
||||
pExaPixmap->pDamage = DamageCreate(exaDamageReport_mixed, NULL,
|
||||
DamageReportNonEmpty, TRUE,
|
||||
pPixmap->drawable.pScreen,
|
||||
pPixmap);
|
||||
|
||||
if (pExaPixmap->pDamage) {
|
||||
DamageRegister(&pPixmap->drawable, pExaPixmap->pDamage);
|
||||
/* This ensures that pending damage reflects the current
|
||||
* operation. This is used by exa to optimize migration.
|
||||
*/
|
||||
DamageSetReportAfterOp(pExaPixmap->pDamage, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* During a fallback we must prepare access. */
|
||||
if (pExaScr->fallback_counter)
|
||||
exaPrepareAccess(&pPixmap->drawable, EXA_PREPARE_AUX_DEST);
|
||||
|
||||
return pPixmap;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
|
||||
int bitsPerPixel, int devKind, void *pPixData)
|
||||
{
|
||||
ScreenPtr pScreen;
|
||||
ExaScreenPrivPtr pExaScr;
|
||||
ExaPixmapPrivPtr pExaPixmap;
|
||||
Bool ret, has_gpu_copy;
|
||||
|
||||
if (!pPixmap)
|
||||
return FALSE;
|
||||
|
||||
pScreen = pPixmap->drawable.pScreen;
|
||||
pExaScr = ExaGetScreenPriv(pScreen);
|
||||
pExaPixmap = ExaGetPixmapPriv(pPixmap);
|
||||
|
||||
if (pPixData) {
|
||||
if (pExaPixmap->driverPriv) {
|
||||
if (pExaPixmap->pDamage) {
|
||||
DamageDestroy(pExaPixmap->pDamage);
|
||||
pExaPixmap->pDamage = NULL;
|
||||
}
|
||||
|
||||
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
}
|
||||
|
||||
pExaPixmap->use_gpu_copy = FALSE;
|
||||
pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
|
||||
}
|
||||
|
||||
has_gpu_copy = exaPixmapHasGpuCopy(pPixmap);
|
||||
|
||||
if (width <= 0)
|
||||
width = pPixmap->drawable.width;
|
||||
|
||||
if (height <= 0)
|
||||
height = pPixmap->drawable.height;
|
||||
|
||||
if (bitsPerPixel <= 0) {
|
||||
if (depth <= 0)
|
||||
bitsPerPixel = pPixmap->drawable.bitsPerPixel;
|
||||
else
|
||||
bitsPerPixel = BitsPerPixel(depth);
|
||||
}
|
||||
|
||||
if (depth <= 0)
|
||||
depth = pPixmap->drawable.depth;
|
||||
|
||||
if (width != pPixmap->drawable.width ||
|
||||
height != pPixmap->drawable.height ||
|
||||
depth != pPixmap->drawable.depth ||
|
||||
bitsPerPixel != pPixmap->drawable.bitsPerPixel) {
|
||||
if (pExaPixmap->driverPriv) {
|
||||
if (devKind > 0)
|
||||
pExaPixmap->fb_pitch = devKind;
|
||||
else
|
||||
exaSetFbPitch(pExaScr, pExaPixmap, width, height, bitsPerPixel);
|
||||
|
||||
exaSetAccelBlock(pExaScr, pExaPixmap, width, height, bitsPerPixel);
|
||||
RegionEmpty(&pExaPixmap->validFB);
|
||||
}
|
||||
|
||||
/* Need to re-create system copy if there's also a GPU copy */
|
||||
if (has_gpu_copy) {
|
||||
if (pExaPixmap->sys_ptr) {
|
||||
free(pExaPixmap->sys_ptr);
|
||||
pExaPixmap->sys_ptr = NULL;
|
||||
DamageDestroy(pExaPixmap->pDamage);
|
||||
pExaPixmap->pDamage = NULL;
|
||||
RegionEmpty(&pExaPixmap->validSys);
|
||||
|
||||
if (pExaScr->deferred_mixed_pixmap == pPixmap)
|
||||
pExaScr->deferred_mixed_pixmap = NULL;
|
||||
}
|
||||
|
||||
pExaPixmap->sys_pitch = PixmapBytePad(width, depth);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_gpu_copy) {
|
||||
pPixmap->devPrivate.ptr = pExaPixmap->fb_ptr;
|
||||
pPixmap->devKind = pExaPixmap->fb_pitch;
|
||||
}
|
||||
else {
|
||||
pPixmap->devPrivate.ptr = pExaPixmap->sys_ptr;
|
||||
pPixmap->devKind = pExaPixmap->sys_pitch;
|
||||
}
|
||||
|
||||
/* Only pass driver pixmaps to the driver. */
|
||||
if (pExaScr->info->ModifyPixmapHeader && pExaPixmap->driverPriv) {
|
||||
ret = pExaScr->info->ModifyPixmapHeader(pPixmap, width, height, depth,
|
||||
bitsPerPixel, devKind,
|
||||
pPixData);
|
||||
if (ret == TRUE)
|
||||
goto out;
|
||||
}
|
||||
|
||||
swap(pExaScr, pScreen, ModifyPixmapHeader);
|
||||
ret = pScreen->ModifyPixmapHeader(pPixmap, width, height, depth,
|
||||
bitsPerPixel, devKind, pPixData);
|
||||
swap(pExaScr, pScreen, ModifyPixmapHeader);
|
||||
|
||||
out:
|
||||
if (has_gpu_copy) {
|
||||
pExaPixmap->fb_ptr = pPixmap->devPrivate.ptr;
|
||||
pExaPixmap->fb_pitch = pPixmap->devKind;
|
||||
}
|
||||
else {
|
||||
pExaPixmap->sys_ptr = pPixmap->devPrivate.ptr;
|
||||
pExaPixmap->sys_pitch = pPixmap->devKind;
|
||||
}
|
||||
/* Always NULL this, we don't want lingering pointers. */
|
||||
pPixmap->devPrivate.ptr = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaDestroyPixmap_mixed(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
Bool ret;
|
||||
|
||||
if (pPixmap->refcnt == 1) {
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
exaDestroyPixmap(pPixmap);
|
||||
|
||||
if (pExaScr->deferred_mixed_pixmap == pPixmap)
|
||||
pExaScr->deferred_mixed_pixmap = NULL;
|
||||
|
||||
if (pExaPixmap->driverPriv)
|
||||
pExaScr->info->DestroyPixmap(pScreen, pExaPixmap->driverPriv);
|
||||
pExaPixmap->driverPriv = NULL;
|
||||
|
||||
if (pExaPixmap->pDamage) {
|
||||
free(pExaPixmap->sys_ptr);
|
||||
pExaPixmap->sys_ptr = NULL;
|
||||
pExaPixmap->pDamage = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
ret = pScreen->DestroyPixmap(pPixmap);
|
||||
swap(pExaScr, pScreen, DestroyPixmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaPixmapPriv(pPixmap);
|
||||
void *saved_ptr;
|
||||
Bool ret;
|
||||
|
||||
if (!pExaPixmap->driverPriv)
|
||||
return FALSE;
|
||||
|
||||
saved_ptr = pPixmap->devPrivate.ptr;
|
||||
pPixmap->devPrivate.ptr = ExaGetPixmapAddress(pPixmap);
|
||||
ret = pExaScr->info->PixmapIsOffscreen(pPixmap);
|
||||
pPixmap->devPrivate.ptr = saved_ptr;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaSharePixmapBacking_mixed(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
ExaScreenPriv(pScreen);
|
||||
Bool ret = FALSE;
|
||||
|
||||
exaMoveInPixmap(pPixmap);
|
||||
/* get the driver to give us a handle */
|
||||
if (pExaScr->info->SharePixmapBacking)
|
||||
ret = pExaScr->info->SharePixmapBacking(pPixmap, secondary, handle_p);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool
|
||||
exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap, void *handle)
|
||||
{
|
||||
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
||||
ExaScreenPriv(pScreen);
|
||||
Bool ret = FALSE;
|
||||
|
||||
if (pExaScr->info->SetSharedPixmapBacking)
|
||||
ret = pExaScr->info->SetSharedPixmapBacking(pPixmap, handle);
|
||||
|
||||
if (ret == TRUE)
|
||||
exaMoveInPixmap(pPixmap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,677 @@
|
|||
/*
|
||||
* Copyright © 2003 Anders Carlsson
|
||||
*
|
||||
* 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 Anders Carlsson not be used in
|
||||
* advertising or publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. Anders Carlsson makes no
|
||||
* representations about the suitability of this software for any purpose. It
|
||||
* is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* ANDERS CARLSSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL ANDERS CARLSSON 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.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* This allocator allocates blocks of memory by maintaining a list of areas.
|
||||
* When allocating, the contiguous block of areas with the minimum eviction
|
||||
* cost is found and evicted in order to make room for the new allocation.
|
||||
*/
|
||||
|
||||
#include "exa_priv.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if DEBUG_OFFSCREEN
|
||||
#define DBG_OFFSCREEN(a) ErrorF a
|
||||
#else
|
||||
#define DBG_OFFSCREEN(a)
|
||||
#endif
|
||||
|
||||
#if DEBUG_OFFSCREEN
|
||||
static void
|
||||
ExaOffscreenValidate(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaOffscreenArea *prev = 0, *area;
|
||||
|
||||
assert(pExaScr->info->offScreenAreas->base_offset ==
|
||||
pExaScr->info->offScreenBase);
|
||||
for (area = pExaScr->info->offScreenAreas; area; area = area->next) {
|
||||
assert(area->offset >= area->base_offset);
|
||||
assert(area->offset < (area->base_offset + area->size));
|
||||
if (prev)
|
||||
assert(prev->base_offset + prev->size == area->base_offset);
|
||||
prev = area;
|
||||
}
|
||||
assert(prev->base_offset + prev->size == pExaScr->info->memorySize);
|
||||
}
|
||||
#else
|
||||
#define ExaOffscreenValidate(s)
|
||||
#endif
|
||||
|
||||
static ExaOffscreenArea *
|
||||
ExaOffscreenKickOut(ScreenPtr pScreen, ExaOffscreenArea * area)
|
||||
{
|
||||
if (area->save)
|
||||
(*area->save) (pScreen, area);
|
||||
return exaOffscreenFree(pScreen, area);
|
||||
}
|
||||
|
||||
static void
|
||||
exaUpdateEvictionCost(ExaOffscreenArea * area, unsigned offScreenCounter)
|
||||
{
|
||||
unsigned age;
|
||||
|
||||
if (area->state == ExaOffscreenAvail)
|
||||
return;
|
||||
|
||||
age = offScreenCounter - area->last_use;
|
||||
|
||||
/* This is unlikely to happen, but could result in a division by zero... */
|
||||
if (age > (UINT_MAX / 2)) {
|
||||
age = UINT_MAX / 2;
|
||||
area->last_use = offScreenCounter - age;
|
||||
}
|
||||
|
||||
area->eviction_cost = area->size / age;
|
||||
}
|
||||
|
||||
static ExaOffscreenArea *
|
||||
exaFindAreaToEvict(ExaScreenPrivPtr pExaScr, int size, int align)
|
||||
{
|
||||
ExaOffscreenArea *begin, *end, *best;
|
||||
unsigned cost, best_cost;
|
||||
int avail, real_size;
|
||||
|
||||
best_cost = UINT_MAX;
|
||||
begin = end = pExaScr->info->offScreenAreas;
|
||||
avail = 0;
|
||||
cost = 0;
|
||||
best = 0;
|
||||
|
||||
while (end != NULL) {
|
||||
restart:
|
||||
while (begin != NULL && begin->state == ExaOffscreenLocked)
|
||||
begin = end = begin->next;
|
||||
|
||||
if (begin == NULL)
|
||||
break;
|
||||
|
||||
/* adjust size needed to account for alignment loss for this area */
|
||||
real_size = size + (begin->base_offset + begin->size - size) % align;
|
||||
|
||||
while (avail < real_size && end != NULL) {
|
||||
if (end->state == ExaOffscreenLocked) {
|
||||
/* Can't more room here, restart after this locked area */
|
||||
avail = 0;
|
||||
cost = 0;
|
||||
begin = end;
|
||||
goto restart;
|
||||
}
|
||||
avail += end->size;
|
||||
exaUpdateEvictionCost(end, pExaScr->offScreenCounter);
|
||||
cost += end->eviction_cost;
|
||||
end = end->next;
|
||||
}
|
||||
|
||||
/* Check the cost, update best */
|
||||
if (avail >= real_size && cost < best_cost) {
|
||||
best = begin;
|
||||
best_cost = cost;
|
||||
}
|
||||
|
||||
avail -= begin->size;
|
||||
cost -= begin->eviction_cost;
|
||||
begin = begin->next;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
/**
|
||||
* exaOffscreenAlloc allocates offscreen memory
|
||||
*
|
||||
* @param pScreen current screen
|
||||
* @param size size in bytes of the allocation
|
||||
* @param align byte alignment requirement for the offset of the allocated area
|
||||
* @param locked whether the allocated area is locked and can't be kicked out
|
||||
* @param save callback for when the area is evicted from memory
|
||||
* @param privdata private data for the save callback.
|
||||
*
|
||||
* Allocates offscreen memory from the device associated with pScreen. size
|
||||
* and align determine where and how large the allocated area is, and locked
|
||||
* will mark whether it should be held in card memory. privdata may be any
|
||||
* pointer for the save callback when the area is removed.
|
||||
*
|
||||
* Note that locked areas do get evicted on VT switch unless the driver
|
||||
* requested version 2.1 or newer behavior. In that case, the save callback is
|
||||
* still called.
|
||||
*/
|
||||
ExaOffscreenArea *
|
||||
exaOffscreenAlloc(ScreenPtr pScreen, int size, int align,
|
||||
Bool locked, ExaOffscreenSaveProc save, void *privData)
|
||||
{
|
||||
ExaOffscreenArea *area;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
int real_size = 0, largest_avail = 0;
|
||||
|
||||
#if DEBUG_OFFSCREEN
|
||||
static int number = 0;
|
||||
|
||||
ErrorF("================= ============ allocating a new pixmap %d\n",
|
||||
++number);
|
||||
#endif
|
||||
|
||||
ExaOffscreenValidate(pScreen);
|
||||
if (!align)
|
||||
align = 1;
|
||||
|
||||
if (!size) {
|
||||
DBG_OFFSCREEN(("Alloc 0x%x -> EMPTY\n", size));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* throw out requests that cannot fit */
|
||||
if (size > (pExaScr->info->memorySize - pExaScr->info->offScreenBase)) {
|
||||
DBG_OFFSCREEN(("Alloc 0x%x vs (0x%lx) -> TOBIG\n", size,
|
||||
pExaScr->info->memorySize -
|
||||
pExaScr->info->offScreenBase));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Try to find a free space that'll fit. */
|
||||
for (area = pExaScr->info->offScreenAreas; area; area = area->next) {
|
||||
/* skip allocated areas */
|
||||
if (area->state != ExaOffscreenAvail)
|
||||
continue;
|
||||
|
||||
/* adjust size to match alignment requirement */
|
||||
real_size = size + (area->base_offset + area->size - size) % align;
|
||||
|
||||
/* does it fit? */
|
||||
if (real_size <= area->size)
|
||||
break;
|
||||
|
||||
if (area->size > largest_avail)
|
||||
largest_avail = area->size;
|
||||
}
|
||||
|
||||
if (!area) {
|
||||
area = exaFindAreaToEvict(pExaScr, size, align);
|
||||
|
||||
if (!area) {
|
||||
DBG_OFFSCREEN(("Alloc 0x%x -> NOSPACE\n", size));
|
||||
/* Could not allocate memory */
|
||||
ExaOffscreenValidate(pScreen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* adjust size needed to account for alignment loss for this area */
|
||||
real_size = size + (area->base_offset + area->size - size) % align;
|
||||
|
||||
/*
|
||||
* Kick out first area if in use
|
||||
*/
|
||||
if (area->state != ExaOffscreenAvail)
|
||||
area = ExaOffscreenKickOut(pScreen, area);
|
||||
/*
|
||||
* Now get the system to merge the other needed areas together
|
||||
*/
|
||||
while (area->size < real_size) {
|
||||
assert(area->next);
|
||||
assert(area->next->state == ExaOffscreenRemovable);
|
||||
(void) ExaOffscreenKickOut(pScreen, area->next);
|
||||
}
|
||||
}
|
||||
|
||||
/* save extra space in new area */
|
||||
if (real_size < area->size) {
|
||||
ExaOffscreenArea *new_area = malloc(sizeof(ExaOffscreenArea));
|
||||
|
||||
if (!new_area)
|
||||
return NULL;
|
||||
new_area->base_offset = area->base_offset;
|
||||
|
||||
new_area->offset = new_area->base_offset;
|
||||
new_area->align = 0;
|
||||
new_area->size = area->size - real_size;
|
||||
new_area->state = ExaOffscreenAvail;
|
||||
new_area->save = NULL;
|
||||
new_area->last_use = 0;
|
||||
new_area->eviction_cost = 0;
|
||||
new_area->next = area;
|
||||
new_area->prev = area->prev;
|
||||
if (area->prev->next)
|
||||
area->prev->next = new_area;
|
||||
else
|
||||
pExaScr->info->offScreenAreas = new_area;
|
||||
area->prev = new_area;
|
||||
area->base_offset = new_area->base_offset + new_area->size;
|
||||
area->size = real_size;
|
||||
}
|
||||
else
|
||||
pExaScr->numOffscreenAvailable--;
|
||||
|
||||
/*
|
||||
* Mark this area as in use
|
||||
*/
|
||||
if (locked)
|
||||
area->state = ExaOffscreenLocked;
|
||||
else
|
||||
area->state = ExaOffscreenRemovable;
|
||||
area->privData = privData;
|
||||
area->save = save;
|
||||
area->last_use = pExaScr->offScreenCounter++;
|
||||
area->offset = (area->base_offset + align - 1);
|
||||
area->offset -= area->offset % align;
|
||||
area->align = align;
|
||||
|
||||
ExaOffscreenValidate(pScreen);
|
||||
|
||||
DBG_OFFSCREEN(("Alloc 0x%x -> 0x%x (0x%x)\n", size,
|
||||
area->base_offset, area->offset));
|
||||
return area;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejects all offscreen areas, and uninitializes the offscreen memory manager.
|
||||
*/
|
||||
void
|
||||
ExaOffscreenSwapOut(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
ExaOffscreenValidate(pScreen);
|
||||
/* loop until a single free area spans the space */
|
||||
for (;;) {
|
||||
ExaOffscreenArea *area = pExaScr->info->offScreenAreas;
|
||||
|
||||
if (!area)
|
||||
break;
|
||||
if (area->state == ExaOffscreenAvail) {
|
||||
area = area->next;
|
||||
if (!area)
|
||||
break;
|
||||
}
|
||||
assert(area->state != ExaOffscreenAvail);
|
||||
(void) ExaOffscreenKickOut(pScreen, area);
|
||||
ExaOffscreenValidate(pScreen);
|
||||
}
|
||||
ExaOffscreenValidate(pScreen);
|
||||
ExaOffscreenFini(pScreen);
|
||||
}
|
||||
|
||||
/** Ejects all pixmaps managed by EXA. */
|
||||
static void
|
||||
ExaOffscreenEjectPixmaps(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
ExaOffscreenValidate(pScreen);
|
||||
/* loop until a single free area spans the space */
|
||||
for (;;) {
|
||||
ExaOffscreenArea *area;
|
||||
|
||||
for (area = pExaScr->info->offScreenAreas; area != NULL;
|
||||
area = area->next) {
|
||||
if (area->state == ExaOffscreenRemovable &&
|
||||
area->save == exaPixmapSave) {
|
||||
(void) ExaOffscreenKickOut(pScreen, area);
|
||||
ExaOffscreenValidate(pScreen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (area == NULL)
|
||||
break;
|
||||
}
|
||||
ExaOffscreenValidate(pScreen);
|
||||
}
|
||||
|
||||
void
|
||||
ExaOffscreenSwapIn(ScreenPtr pScreen)
|
||||
{
|
||||
exaOffscreenInit(pScreen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares EXA for disabling of FB access, or restoring it.
|
||||
*
|
||||
* In version 2.1, the disabling results in pixmaps being ejected, while other
|
||||
* allocations remain. With this plus the prevention of migration while
|
||||
* swappedOut is set, EXA by itself should not cause any access of the
|
||||
* framebuffer to occur while swapped out. Any remaining issues are the
|
||||
* responsibility of the driver.
|
||||
*
|
||||
* Prior to version 2.1, all allocations, including locked ones, are ejected
|
||||
* when access is disabled, and the allocator is torn down while swappedOut
|
||||
* is set. This is more drastic, and caused implementation difficulties for
|
||||
* many drivers that could otherwise handle the lack of FB access while
|
||||
* swapped out.
|
||||
*/
|
||||
void
|
||||
exaEnableDisableFBAccess(ScreenPtr pScreen, Bool enable)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
if (pExaScr->info->flags & EXA_HANDLES_PIXMAPS)
|
||||
return;
|
||||
|
||||
if (!enable && pExaScr->disableFbCount++ == 0) {
|
||||
if (pExaScr->info->exa_minor < 1)
|
||||
ExaOffscreenSwapOut(pScreen);
|
||||
else
|
||||
ExaOffscreenEjectPixmaps(pScreen);
|
||||
pExaScr->swappedOut = TRUE;
|
||||
}
|
||||
|
||||
if (enable && --pExaScr->disableFbCount == 0) {
|
||||
if (pExaScr->info->exa_minor < 1)
|
||||
ExaOffscreenSwapIn(pScreen);
|
||||
pExaScr->swappedOut = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* merge the next free area into this one */
|
||||
static void
|
||||
ExaOffscreenMerge(ExaScreenPrivPtr pExaScr, ExaOffscreenArea * area)
|
||||
{
|
||||
ExaOffscreenArea *next = area->next;
|
||||
|
||||
/* account for space */
|
||||
area->size += next->size;
|
||||
/* frob pointer */
|
||||
area->next = next->next;
|
||||
if (area->next)
|
||||
area->next->prev = area;
|
||||
else
|
||||
pExaScr->info->offScreenAreas->prev = area;
|
||||
free(next);
|
||||
|
||||
pExaScr->numOffscreenAvailable--;
|
||||
}
|
||||
|
||||
/**
|
||||
* exaOffscreenFree frees an allocation.
|
||||
*
|
||||
* @param pScreen current screen
|
||||
* @param area offscreen area to free
|
||||
*
|
||||
* exaOffscreenFree frees an allocation created by exaOffscreenAlloc. Note that
|
||||
* the save callback of the area is not called, and it is up to the driver to
|
||||
* do any cleanup necessary as a result.
|
||||
*
|
||||
* @return pointer to the newly freed area. This behavior should not be relied
|
||||
* on.
|
||||
*/
|
||||
ExaOffscreenArea *
|
||||
exaOffscreenFree(ScreenPtr pScreen, ExaOffscreenArea * area)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaOffscreenArea *next = area->next;
|
||||
ExaOffscreenArea *prev;
|
||||
|
||||
DBG_OFFSCREEN(("Free 0x%x -> 0x%x (0x%x)\n", area->size,
|
||||
area->base_offset, area->offset));
|
||||
ExaOffscreenValidate(pScreen);
|
||||
|
||||
area->state = ExaOffscreenAvail;
|
||||
area->save = NULL;
|
||||
area->last_use = 0;
|
||||
area->eviction_cost = 0;
|
||||
/*
|
||||
* Find previous area
|
||||
*/
|
||||
if (area == pExaScr->info->offScreenAreas)
|
||||
prev = NULL;
|
||||
else
|
||||
prev = area->prev;
|
||||
|
||||
pExaScr->numOffscreenAvailable++;
|
||||
|
||||
/* link with next area if free */
|
||||
if (next && next->state == ExaOffscreenAvail)
|
||||
ExaOffscreenMerge(pExaScr, area);
|
||||
|
||||
/* link with prev area if free */
|
||||
if (prev && prev->state == ExaOffscreenAvail) {
|
||||
area = prev;
|
||||
ExaOffscreenMerge(pExaScr, area);
|
||||
}
|
||||
|
||||
ExaOffscreenValidate(pScreen);
|
||||
DBG_OFFSCREEN(("\tdone freeing\n"));
|
||||
return area;
|
||||
}
|
||||
|
||||
void
|
||||
ExaOffscreenMarkUsed(PixmapPtr pPixmap)
|
||||
{
|
||||
ExaPixmapPriv(pPixmap);
|
||||
ExaScreenPriv(pPixmap->drawable.pScreen);
|
||||
|
||||
if (!pExaPixmap || !pExaPixmap->area)
|
||||
return;
|
||||
|
||||
pExaPixmap->area->last_use = pExaScr->offScreenCounter++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defragment offscreen memory by compacting allocated areas at the end of it,
|
||||
* leaving the total amount of memory available as a single area at the
|
||||
* beginning (when there are no pinned allocations).
|
||||
*/
|
||||
_X_HIDDEN ExaOffscreenArea *
|
||||
ExaOffscreenDefragment(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaOffscreenArea *area, *largest_available = NULL;
|
||||
int largest_size = 0;
|
||||
PixmapPtr pDstPix;
|
||||
ExaPixmapPrivPtr pExaDstPix;
|
||||
|
||||
pDstPix = (*pScreen->CreatePixmap) (pScreen, 0, 0, 0, 0);
|
||||
|
||||
if (!pDstPix)
|
||||
return NULL;
|
||||
|
||||
pExaDstPix = ExaGetPixmapPriv(pDstPix);
|
||||
pExaDstPix->use_gpu_copy = TRUE;
|
||||
|
||||
for (area = pExaScr->info->offScreenAreas->prev;
|
||||
area != pExaScr->info->offScreenAreas;) {
|
||||
ExaOffscreenArea *prev = area->prev;
|
||||
PixmapPtr pSrcPix;
|
||||
ExaPixmapPrivPtr pExaSrcPix;
|
||||
Bool save_use_gpu_copy;
|
||||
int save_pitch;
|
||||
|
||||
if (area->state != ExaOffscreenAvail ||
|
||||
prev->state == ExaOffscreenLocked ||
|
||||
(prev->state == ExaOffscreenRemovable &&
|
||||
prev->save != exaPixmapSave)) {
|
||||
area = prev;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prev->state == ExaOffscreenAvail) {
|
||||
if (area == largest_available) {
|
||||
largest_available = prev;
|
||||
largest_size += prev->size;
|
||||
}
|
||||
area = prev;
|
||||
ExaOffscreenMerge(pExaScr, area);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (area->size > largest_size) {
|
||||
largest_available = area;
|
||||
largest_size = area->size;
|
||||
}
|
||||
|
||||
pSrcPix = prev->privData;
|
||||
pExaSrcPix = ExaGetPixmapPriv(pSrcPix);
|
||||
|
||||
pExaDstPix->fb_ptr = pExaScr->info->memoryBase +
|
||||
area->base_offset + area->size - prev->size + prev->base_offset -
|
||||
prev->offset;
|
||||
pExaDstPix->fb_ptr -= (unsigned long) pExaDstPix->fb_ptr % prev->align;
|
||||
|
||||
if (pExaDstPix->fb_ptr <= pExaSrcPix->fb_ptr) {
|
||||
area = prev;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(pExaScr->info->flags & EXA_SUPPORTS_OFFSCREEN_OVERLAPS) &&
|
||||
(pExaSrcPix->fb_ptr + prev->size) > pExaDstPix->fb_ptr) {
|
||||
area = prev;
|
||||
continue;
|
||||
}
|
||||
|
||||
save_use_gpu_copy = pExaSrcPix->use_gpu_copy;
|
||||
save_pitch = pSrcPix->devKind;
|
||||
|
||||
pExaSrcPix->use_gpu_copy = TRUE;
|
||||
pSrcPix->devKind = pExaSrcPix->fb_pitch;
|
||||
|
||||
pDstPix->drawable.width = pSrcPix->drawable.width;
|
||||
pDstPix->devKind = pSrcPix->devKind;
|
||||
pDstPix->drawable.height = pSrcPix->drawable.height;
|
||||
pDstPix->drawable.depth = pSrcPix->drawable.depth;
|
||||
pDstPix->drawable.bitsPerPixel = pSrcPix->drawable.bitsPerPixel;
|
||||
|
||||
if (!pExaScr->info->PrepareCopy(pSrcPix, pDstPix, -1, -1, GXcopy, ~0)) {
|
||||
pExaSrcPix->use_gpu_copy = save_use_gpu_copy;
|
||||
pSrcPix->devKind = save_pitch;
|
||||
area = prev;
|
||||
continue;
|
||||
}
|
||||
|
||||
pExaScr->info->Copy(pDstPix, 0, 0, 0, 0, pDstPix->drawable.width,
|
||||
pDstPix->drawable.height);
|
||||
pExaScr->info->DoneCopy(pDstPix);
|
||||
exaMarkSync(pScreen);
|
||||
|
||||
DBG_OFFSCREEN(("Before swap: prev=0x%08x-0x%08x-0x%08x area=0x%08x-0x%08x-0x%08x\n", prev->base_offset, prev->offset, prev->base_offset + prev->size, area->base_offset, area->offset, area->base_offset + area->size));
|
||||
|
||||
/* Calculate swapped area offsets and sizes */
|
||||
area->base_offset = prev->base_offset;
|
||||
area->offset = area->base_offset;
|
||||
prev->offset += pExaDstPix->fb_ptr - pExaSrcPix->fb_ptr;
|
||||
assert(prev->offset >= pExaScr->info->offScreenBase);
|
||||
assert(prev->offset < pExaScr->info->memorySize);
|
||||
prev->base_offset = prev->offset;
|
||||
if (area->next)
|
||||
prev->size = area->next->base_offset - prev->base_offset;
|
||||
else
|
||||
prev->size = pExaScr->info->memorySize - prev->base_offset;
|
||||
area->size = prev->base_offset - area->base_offset;
|
||||
|
||||
DBG_OFFSCREEN(("After swap: area=0x%08x-0x%08x-0x%08x prev=0x%08x-0x%08x-0x%08x\n", area->base_offset, area->offset, area->base_offset + area->size, prev->base_offset, prev->offset, prev->base_offset + prev->size));
|
||||
|
||||
/* Swap areas in list */
|
||||
if (area->next)
|
||||
area->next->prev = prev;
|
||||
else
|
||||
pExaScr->info->offScreenAreas->prev = prev;
|
||||
if (prev->prev->next)
|
||||
prev->prev->next = area;
|
||||
else
|
||||
pExaScr->info->offScreenAreas = area;
|
||||
prev->next = area->next;
|
||||
area->next = prev;
|
||||
area->prev = prev->prev;
|
||||
prev->prev = area;
|
||||
if (!area->prev->next)
|
||||
pExaScr->info->offScreenAreas = area;
|
||||
|
||||
#if DEBUG_OFFSCREEN
|
||||
if (prev->prev == prev || prev->next == prev)
|
||||
ErrorF("Whoops, prev points to itself!\n");
|
||||
|
||||
if (area->prev == area || area->next == area)
|
||||
ErrorF("Whoops, area points to itself!\n");
|
||||
#endif
|
||||
|
||||
pExaSrcPix->fb_ptr = pExaDstPix->fb_ptr;
|
||||
pExaSrcPix->use_gpu_copy = save_use_gpu_copy;
|
||||
pSrcPix->devKind = save_pitch;
|
||||
}
|
||||
|
||||
pDstPix->drawable.width = 0;
|
||||
pDstPix->drawable.height = 0;
|
||||
pDstPix->drawable.depth = 0;
|
||||
pDstPix->drawable.bitsPerPixel = 0;
|
||||
|
||||
(*pScreen->DestroyPixmap) (pDstPix);
|
||||
|
||||
if (area->state == ExaOffscreenAvail && area->size > largest_size)
|
||||
return area;
|
||||
|
||||
return largest_available;
|
||||
}
|
||||
|
||||
/**
|
||||
* exaOffscreenInit initializes the offscreen memory manager.
|
||||
*
|
||||
* @param pScreen current screen
|
||||
*
|
||||
* exaOffscreenInit is called by exaDriverInit to set up the memory manager for
|
||||
* the screen, if any offscreen memory is available.
|
||||
*/
|
||||
Bool
|
||||
exaOffscreenInit(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaOffscreenArea *area;
|
||||
|
||||
/* Allocate a big free area */
|
||||
area = malloc(sizeof(ExaOffscreenArea));
|
||||
|
||||
if (!area)
|
||||
return FALSE;
|
||||
|
||||
area->state = ExaOffscreenAvail;
|
||||
area->base_offset = pExaScr->info->offScreenBase;
|
||||
area->offset = area->base_offset;
|
||||
area->align = 0;
|
||||
area->size = pExaScr->info->memorySize - area->base_offset;
|
||||
area->save = NULL;
|
||||
area->next = NULL;
|
||||
area->prev = area;
|
||||
area->last_use = 0;
|
||||
area->eviction_cost = 0;
|
||||
|
||||
/* Add it to the free areas */
|
||||
pExaScr->info->offScreenAreas = area;
|
||||
pExaScr->offScreenCounter = 1;
|
||||
pExaScr->numOffscreenAvailable = 1;
|
||||
|
||||
ExaOffscreenValidate(pScreen);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
ExaOffscreenFini(ScreenPtr pScreen)
|
||||
{
|
||||
ExaScreenPriv(pScreen);
|
||||
ExaOffscreenArea *area;
|
||||
|
||||
/* just free all of the area records */
|
||||
while ((area = pExaScr->info->offScreenAreas)) {
|
||||
pExaScr->info->offScreenAreas = area->next;
|
||||
free(area);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,735 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (C) 2000 Keith Packard, member of The XFree86 Project, Inc.
|
||||
* 2005 Zack Rusin, Trolltech
|
||||
*
|
||||
* 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 Keith Packard not be used in
|
||||
* advertising or publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. Keith Packard makes no
|
||||
* representations about the suitability of this software for any purpose. It
|
||||
* is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef EXAPRIV_H
|
||||
#define EXAPRIV_H
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include "exa.h"
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xproto.h>
|
||||
#ifdef MITSHM
|
||||
#include "shmint.h"
|
||||
#endif
|
||||
#include "scrnintstr.h"
|
||||
#include "pixmapstr.h"
|
||||
#include "windowstr.h"
|
||||
#include "servermd.h"
|
||||
#include "colormapst.h"
|
||||
#include "gcstruct.h"
|
||||
#include "input.h"
|
||||
#include "mipointer.h"
|
||||
#include "mi.h"
|
||||
#include "dix.h"
|
||||
#include "fb.h"
|
||||
#include "fboverlay.h"
|
||||
#include "fbpict.h"
|
||||
#include "glyphstr.h"
|
||||
#include "damage.h"
|
||||
|
||||
#define DEBUG_TRACE_FALL 0
|
||||
#define DEBUG_MIGRATE 0
|
||||
#define DEBUG_PIXMAP 0
|
||||
#define DEBUG_OFFSCREEN 0
|
||||
#define DEBUG_GLYPH_CACHE 0
|
||||
|
||||
#if DEBUG_TRACE_FALL
|
||||
#define EXA_FALLBACK(x) \
|
||||
do { \
|
||||
ErrorF("EXA fallback at %s: ", __FUNCTION__); \
|
||||
ErrorF x; \
|
||||
} while (0)
|
||||
|
||||
char
|
||||
exaDrawableLocation(DrawablePtr pDrawable);
|
||||
#else
|
||||
#define EXA_FALLBACK(x)
|
||||
#endif
|
||||
|
||||
#if DEBUG_PIXMAP
|
||||
#define DBG_PIXMAP(a) ErrorF a
|
||||
#else
|
||||
#define DBG_PIXMAP(a)
|
||||
#endif
|
||||
|
||||
#ifndef EXA_MAX_FB
|
||||
#define EXA_MAX_FB FB_OVERLAY_MAX
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define EXA_FatalErrorDebug(x) FatalError x
|
||||
#define EXA_FatalErrorDebugWithRet(x, ret) FatalError x
|
||||
#else
|
||||
#define EXA_FatalErrorDebug(x) ErrorF x
|
||||
#define EXA_FatalErrorDebugWithRet(x, ret) \
|
||||
do { \
|
||||
ErrorF x; \
|
||||
return ret; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This is the list of migration heuristics supported by EXA. See
|
||||
* exaDoMigration() for what their implementations do.
|
||||
*/
|
||||
enum ExaMigrationHeuristic {
|
||||
ExaMigrationGreedy,
|
||||
ExaMigrationAlways,
|
||||
ExaMigrationSmart
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned char sha1[20];
|
||||
} ExaCachedGlyphRec, *ExaCachedGlyphPtr;
|
||||
|
||||
typedef struct {
|
||||
/* The identity of the cache, statically configured at initialization */
|
||||
unsigned int format;
|
||||
int glyphWidth;
|
||||
int glyphHeight;
|
||||
|
||||
int size; /* Size of cache; eventually this should be dynamically determined */
|
||||
|
||||
/* Hash table mapping from glyph sha1 to position in the glyph; we use
|
||||
* open addressing with a hash table size determined based on size and large
|
||||
* enough so that we always have a good amount of free space, so we can
|
||||
* use linear probing. (Linear probing is preferable to double hashing
|
||||
* here because it allows us to easily remove entries.)
|
||||
*/
|
||||
int *hashEntries;
|
||||
int hashSize;
|
||||
|
||||
ExaCachedGlyphPtr glyphs;
|
||||
int glyphCount; /* Current number of glyphs */
|
||||
|
||||
PicturePtr picture; /* Where the glyphs of the cache are stored */
|
||||
int yOffset; /* y location within the picture where the cache starts */
|
||||
int columns; /* Number of columns the glyphs are laid out in */
|
||||
int evictionPosition; /* Next random position to evict a glyph */
|
||||
} ExaGlyphCacheRec, *ExaGlyphCachePtr;
|
||||
|
||||
#define EXA_NUM_GLYPH_CACHES 4
|
||||
|
||||
#define EXA_FALLBACK_COPYWINDOW (1 << 0)
|
||||
#define EXA_ACCEL_COPYWINDOW (1 << 1)
|
||||
|
||||
typedef struct _ExaMigrationRec {
|
||||
Bool as_dst;
|
||||
Bool as_src;
|
||||
PixmapPtr pPix;
|
||||
RegionPtr pReg;
|
||||
} ExaMigrationRec, *ExaMigrationPtr;
|
||||
|
||||
typedef void (*EnableDisableFBAccessProcPtr) (ScreenPtr, Bool);
|
||||
typedef struct {
|
||||
ExaDriverPtr info;
|
||||
ScreenBlockHandlerProcPtr SavedBlockHandler;
|
||||
ScreenWakeupHandlerProcPtr SavedWakeupHandler;
|
||||
CreateGCProcPtr SavedCreateGC;
|
||||
CloseScreenProcPtr SavedCloseScreen;
|
||||
GetImageProcPtr SavedGetImage;
|
||||
GetSpansProcPtr SavedGetSpans;
|
||||
CreatePixmapProcPtr SavedCreatePixmap;
|
||||
DestroyPixmapProcPtr SavedDestroyPixmap;
|
||||
CopyWindowProcPtr SavedCopyWindow;
|
||||
ChangeWindowAttributesProcPtr SavedChangeWindowAttributes;
|
||||
BitmapToRegionProcPtr SavedBitmapToRegion;
|
||||
CreateScreenResourcesProcPtr SavedCreateScreenResources;
|
||||
ModifyPixmapHeaderProcPtr SavedModifyPixmapHeader;
|
||||
SharePixmapBackingProcPtr SavedSharePixmapBacking;
|
||||
SetSharedPixmapBackingProcPtr SavedSetSharedPixmapBacking;
|
||||
SourceValidateProcPtr SavedSourceValidate;
|
||||
CompositeProcPtr SavedComposite;
|
||||
TrianglesProcPtr SavedTriangles;
|
||||
GlyphsProcPtr SavedGlyphs;
|
||||
TrapezoidsProcPtr SavedTrapezoids;
|
||||
AddTrapsProcPtr SavedAddTraps;
|
||||
void (*do_migration) (ExaMigrationPtr pixmaps, int npixmaps,
|
||||
Bool can_accel);
|
||||
Bool (*pixmap_has_gpu_copy) (PixmapPtr pPixmap);
|
||||
void (*do_move_in_pixmap) (PixmapPtr pPixmap);
|
||||
void (*do_move_out_pixmap) (PixmapPtr pPixmap);
|
||||
void (*prepare_access_reg) (PixmapPtr pPixmap, int index, RegionPtr pReg);
|
||||
|
||||
Bool swappedOut;
|
||||
enum ExaMigrationHeuristic migration;
|
||||
Bool checkDirtyCorrectness;
|
||||
unsigned disableFbCount;
|
||||
Bool optimize_migration;
|
||||
unsigned offScreenCounter;
|
||||
unsigned numOffscreenAvailable;
|
||||
CARD32 lastDefragment;
|
||||
CARD32 nextDefragment;
|
||||
PixmapPtr deferred_mixed_pixmap;
|
||||
|
||||
/* Reference counting for accessed pixmaps */
|
||||
struct {
|
||||
PixmapPtr pixmap;
|
||||
int count;
|
||||
Bool retval;
|
||||
} access[EXA_NUM_PREPARE_INDICES];
|
||||
|
||||
/* Holds information on fallbacks that cannot be relayed otherwise. */
|
||||
unsigned int fallback_flags;
|
||||
unsigned int fallback_counter;
|
||||
|
||||
ExaGlyphCacheRec glyphCaches[EXA_NUM_GLYPH_CACHES];
|
||||
|
||||
/**
|
||||
* Regions affected by fallback composite source / mask operations.
|
||||
*/
|
||||
|
||||
RegionRec srcReg;
|
||||
RegionRec maskReg;
|
||||
PixmapPtr srcPix;
|
||||
PixmapPtr maskPix;
|
||||
|
||||
DevPrivateKeyRec pixmapPrivateKeyRec;
|
||||
DevPrivateKeyRec gcPrivateKeyRec;
|
||||
} ExaScreenPrivRec, *ExaScreenPrivPtr;
|
||||
|
||||
extern DevPrivateKeyRec exaScreenPrivateKeyRec;
|
||||
|
||||
#define exaScreenPrivateKey (&exaScreenPrivateKeyRec)
|
||||
|
||||
#define ExaGetScreenPriv(s) ((ExaScreenPrivPtr)dixGetPrivate(&(s)->devPrivates, exaScreenPrivateKey))
|
||||
#define ExaScreenPriv(s) ExaScreenPrivPtr pExaScr = ExaGetScreenPriv(s)
|
||||
|
||||
#define ExaGetGCPriv(gc) ((ExaGCPrivPtr)dixGetPrivateAddr(&(gc)->devPrivates, &ExaGetScreenPriv(gc->pScreen)->gcPrivateKeyRec))
|
||||
#define ExaGCPriv(gc) ExaGCPrivPtr pExaGC = ExaGetGCPriv(gc)
|
||||
|
||||
/*
|
||||
* Some macros to deal with function wrapping.
|
||||
*/
|
||||
#define wrap(priv, real, mem, func) {\
|
||||
priv->Saved##mem = real->mem; \
|
||||
real->mem = func; \
|
||||
}
|
||||
|
||||
#define unwrap(priv, real, mem) {\
|
||||
real->mem = priv->Saved##mem; \
|
||||
}
|
||||
|
||||
#ifdef HAVE_TYPEOF
|
||||
#define swap(priv, real, mem) {\
|
||||
typeof(real->mem) tmp = priv->Saved##mem; \
|
||||
priv->Saved##mem = real->mem; \
|
||||
real->mem = tmp; \
|
||||
}
|
||||
#else
|
||||
#define swap(priv, real, mem) {\
|
||||
const void *tmp = priv->Saved##mem; \
|
||||
priv->Saved##mem = real->mem; \
|
||||
real->mem = tmp; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define EXA_PRE_FALLBACK(_screen_) \
|
||||
ExaScreenPriv(_screen_); \
|
||||
pExaScr->fallback_counter++;
|
||||
|
||||
#define EXA_POST_FALLBACK(_screen_) \
|
||||
pExaScr->fallback_counter--;
|
||||
|
||||
#define EXA_PRE_FALLBACK_GC(_gc_) \
|
||||
ExaScreenPriv(_gc_->pScreen); \
|
||||
ExaGCPriv(_gc_); \
|
||||
pExaScr->fallback_counter++; \
|
||||
swap(pExaGC, _gc_, ops);
|
||||
|
||||
#define EXA_POST_FALLBACK_GC(_gc_) \
|
||||
pExaScr->fallback_counter--; \
|
||||
swap(pExaGC, _gc_, ops);
|
||||
|
||||
/** Align an offset to an arbitrary alignment */
|
||||
#define EXA_ALIGN(offset, align) (((offset) + (align) - 1) - \
|
||||
(((offset) + (align) - 1) % (align)))
|
||||
/** Align an offset to a power-of-two alignment */
|
||||
#define EXA_ALIGN2(offset, align) (((offset) + (align) - 1) & ~((align) - 1))
|
||||
|
||||
#define EXA_PIXMAP_SCORE_MOVE_IN 10
|
||||
#define EXA_PIXMAP_SCORE_MAX 20
|
||||
#define EXA_PIXMAP_SCORE_MOVE_OUT -10
|
||||
#define EXA_PIXMAP_SCORE_MIN -20
|
||||
#define EXA_PIXMAP_SCORE_PINNED 1000
|
||||
#define EXA_PIXMAP_SCORE_INIT 1001
|
||||
|
||||
#define ExaGetPixmapPriv(p) ((ExaPixmapPrivPtr)dixGetPrivateAddr(&(p)->devPrivates, &ExaGetScreenPriv((p)->drawable.pScreen)->pixmapPrivateKeyRec))
|
||||
#define ExaPixmapPriv(p) ExaPixmapPrivPtr pExaPixmap = ExaGetPixmapPriv(p)
|
||||
|
||||
#define EXA_RANGE_PITCH (1 << 0)
|
||||
#define EXA_RANGE_WIDTH (1 << 1)
|
||||
#define EXA_RANGE_HEIGHT (1 << 2)
|
||||
|
||||
typedef struct {
|
||||
ExaOffscreenArea *area;
|
||||
int score; /**< score for the move-in vs move-out heuristic */
|
||||
Bool use_gpu_copy;
|
||||
|
||||
CARD8 *sys_ptr; /**< pointer to pixmap data in system memory */
|
||||
int sys_pitch; /**< pitch of pixmap in system memory */
|
||||
|
||||
CARD8 *fb_ptr; /**< pointer to pixmap data in framebuffer memory */
|
||||
int fb_pitch; /**< pitch of pixmap in framebuffer memory */
|
||||
unsigned int fb_size; /**< size of pixmap in framebuffer memory */
|
||||
|
||||
/**
|
||||
* Holds information about whether this pixmap can be used for
|
||||
* acceleration (== 0) or not (> 0).
|
||||
*
|
||||
* Contains a OR'ed combination of the following values:
|
||||
* EXA_RANGE_PITCH - set if the pixmap's pitch is out of range
|
||||
* EXA_RANGE_WIDTH - set if the pixmap's width is out of range
|
||||
* EXA_RANGE_HEIGHT - set if the pixmap's height is out of range
|
||||
*/
|
||||
unsigned int accel_blocked;
|
||||
|
||||
/**
|
||||
* The damage record contains the areas of the pixmap's current location
|
||||
* (framebuffer or system) that have been damaged compared to the other
|
||||
* location.
|
||||
*/
|
||||
DamagePtr pDamage;
|
||||
/**
|
||||
* The valid regions mark the valid bits (at least, as they're derived from
|
||||
* damage, which may be overreported) of a pixmap's system and FB copies.
|
||||
*/
|
||||
RegionRec validSys, validFB;
|
||||
/**
|
||||
* Driver private storage per EXA pixmap
|
||||
*/
|
||||
void *driverPriv;
|
||||
} ExaPixmapPrivRec, *ExaPixmapPrivPtr;
|
||||
|
||||
typedef struct {
|
||||
/* GC values from the layer below. */
|
||||
const GCOps *Savedops;
|
||||
const GCFuncs *Savedfuncs;
|
||||
} ExaGCPrivRec, *ExaGCPrivPtr;
|
||||
|
||||
typedef struct {
|
||||
PicturePtr pDst;
|
||||
INT16 xSrc;
|
||||
INT16 ySrc;
|
||||
INT16 xMask;
|
||||
INT16 yMask;
|
||||
INT16 xDst;
|
||||
INT16 yDst;
|
||||
INT16 width;
|
||||
INT16 height;
|
||||
} ExaCompositeRectRec, *ExaCompositeRectPtr;
|
||||
|
||||
/**
|
||||
* exaDDXDriverInit must be implemented by the DDX using EXA, and is the place
|
||||
* to set EXA options or hook in screen functions to handle using EXA as the AA.
|
||||
*/
|
||||
void exaDDXDriverInit(ScreenPtr pScreen);
|
||||
|
||||
/* exa_unaccel.c */
|
||||
void
|
||||
exaPrepareAccessGC(GCPtr pGC);
|
||||
|
||||
void
|
||||
exaFinishAccessGC(GCPtr pGC);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
|
||||
DDXPointPtr ppt, int *pwidth, int fSorted);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
|
||||
DDXPointPtr ppt, int *pwidth, int nspans, int fSorted);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
|
||||
int x, int y, int w, int h, int leftPad, int format,
|
||||
char *bits);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckCopyNtoN(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
|
||||
BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
|
||||
Bool upsidedown, Pixel bitplane, void *closure);
|
||||
|
||||
RegionPtr
|
||||
|
||||
ExaCheckCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
|
||||
int srcx, int srcy, int w, int h, int dstx, int dsty);
|
||||
|
||||
RegionPtr
|
||||
|
||||
ExaCheckCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
|
||||
int srcx, int srcy, int w, int h, int dstx, int dsty,
|
||||
unsigned long bitPlane);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
|
||||
DDXPointPtr pptInit);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPolylines(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int mode, int npt, DDXPointPtr ppt);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPolySegment(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int nsegInit, xSegment * pSegInit);
|
||||
|
||||
void
|
||||
ExaCheckPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int nrect, xRectangle *prect);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int x, int y, unsigned int nglyph,
|
||||
CharInfoPtr * ppci, void *pglyphBase);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int x, int y, unsigned int nglyph,
|
||||
CharInfoPtr * ppci, void *pglyphBase);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckPushPixels(GCPtr pGC, PixmapPtr pBitmap,
|
||||
DrawablePtr pDrawable, int w, int h, int x, int y);
|
||||
|
||||
void
|
||||
ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
|
||||
unsigned int format, unsigned long planeMask, char *d);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckGetSpans(DrawablePtr pDrawable,
|
||||
int wMax,
|
||||
DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckAddTraps(PicturePtr pPicture,
|
||||
INT16 x_off, INT16 y_off, int ntrap, xTrap * traps);
|
||||
|
||||
/* exa_accel.c */
|
||||
|
||||
static _X_INLINE Bool
|
||||
exaGCReadsDestination(DrawablePtr pDrawable, unsigned long planemask,
|
||||
unsigned int fillStyle, unsigned char alu,
|
||||
Bool clientClip)
|
||||
{
|
||||
return ((alu != GXcopy && alu != GXclear && alu != GXset &&
|
||||
alu != GXcopyInverted) || fillStyle == FillStippled ||
|
||||
clientClip != FALSE || !EXA_PM_IS_SOLID(pDrawable, planemask));
|
||||
}
|
||||
|
||||
void
|
||||
exaCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc);
|
||||
|
||||
Bool
|
||||
|
||||
exaFillRegionTiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
|
||||
DDXPointPtr pPatOrg, CARD32 planemask, CARD32 alu,
|
||||
Bool clientClip);
|
||||
|
||||
void
|
||||
|
||||
exaGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
|
||||
unsigned int format, unsigned long planeMask, char *d);
|
||||
|
||||
RegionPtr
|
||||
|
||||
exaCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
|
||||
int srcx, int srcy, int width, int height, int dstx, int dsty);
|
||||
|
||||
Bool
|
||||
|
||||
exaHWCopyNtoN(DrawablePtr pSrcDrawable,
|
||||
DrawablePtr pDstDrawable,
|
||||
GCPtr pGC,
|
||||
BoxPtr pbox,
|
||||
int nbox, int dx, int dy, Bool reverse, Bool upsidedown);
|
||||
|
||||
void
|
||||
|
||||
exaCopyNtoN(DrawablePtr pSrcDrawable,
|
||||
DrawablePtr pDstDrawable,
|
||||
GCPtr pGC,
|
||||
BoxPtr pbox,
|
||||
int nbox,
|
||||
int dx,
|
||||
int dy,
|
||||
Bool reverse, Bool upsidedown, Pixel bitplane, void *closure);
|
||||
|
||||
extern const GCOps exaOps;
|
||||
|
||||
void
|
||||
|
||||
ExaCheckComposite(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pMask,
|
||||
PicturePtr pDst,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc,
|
||||
INT16 xMask,
|
||||
INT16 yMask,
|
||||
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
|
||||
|
||||
void
|
||||
|
||||
ExaCheckGlyphs(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pDst,
|
||||
PictFormatPtr maskFormat,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs);
|
||||
|
||||
/* exa_offscreen.c */
|
||||
void
|
||||
ExaOffscreenSwapOut(ScreenPtr pScreen);
|
||||
|
||||
void
|
||||
ExaOffscreenSwapIn(ScreenPtr pScreen);
|
||||
|
||||
ExaOffscreenArea *ExaOffscreenDefragment(ScreenPtr pScreen);
|
||||
|
||||
Bool
|
||||
exaOffscreenInit(ScreenPtr pScreen);
|
||||
|
||||
void
|
||||
ExaOffscreenFini(ScreenPtr pScreen);
|
||||
|
||||
/* exa.c */
|
||||
Bool
|
||||
ExaDoPrepareAccess(PixmapPtr pPixmap, int index);
|
||||
|
||||
void
|
||||
exaPrepareAccess(DrawablePtr pDrawable, int index);
|
||||
|
||||
void
|
||||
exaFinishAccess(DrawablePtr pDrawable, int index);
|
||||
|
||||
void
|
||||
exaDestroyPixmap(PixmapPtr pPixmap);
|
||||
|
||||
void
|
||||
exaPixmapDirty(PixmapPtr pPix, int x1, int y1, int x2, int y2);
|
||||
|
||||
void
|
||||
|
||||
exaGetDrawableDeltas(DrawablePtr pDrawable, PixmapPtr pPixmap,
|
||||
int *xp, int *yp);
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy(PixmapPtr p);
|
||||
|
||||
PixmapPtr
|
||||
exaGetOffscreenPixmap(DrawablePtr pDrawable, int *xp, int *yp);
|
||||
|
||||
PixmapPtr
|
||||
exaGetDrawablePixmap(DrawablePtr pDrawable);
|
||||
|
||||
void
|
||||
|
||||
exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
|
||||
int w, int h, int bpp);
|
||||
|
||||
void
|
||||
|
||||
exaSetAccelBlock(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
|
||||
int w, int h, int bpp);
|
||||
|
||||
void
|
||||
exaDoMigration(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
|
||||
|
||||
Bool
|
||||
exaPixmapIsPinned(PixmapPtr pPix);
|
||||
|
||||
extern const GCFuncs exaGCFuncs;
|
||||
|
||||
/* exa_classic.c */
|
||||
PixmapPtr
|
||||
|
||||
exaCreatePixmap_classic(ScreenPtr pScreen, int w, int h, int depth,
|
||||
unsigned usage_hint);
|
||||
|
||||
Bool
|
||||
|
||||
exaModifyPixmapHeader_classic(PixmapPtr pPixmap, int width, int height,
|
||||
int depth, int bitsPerPixel, int devKind,
|
||||
void *pPixData);
|
||||
|
||||
Bool
|
||||
exaDestroyPixmap_classic(PixmapPtr pPixmap);
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy_classic(PixmapPtr pPixmap);
|
||||
|
||||
/* exa_driver.c */
|
||||
PixmapPtr
|
||||
|
||||
exaCreatePixmap_driver(ScreenPtr pScreen, int w, int h, int depth,
|
||||
unsigned usage_hint);
|
||||
|
||||
Bool
|
||||
|
||||
exaModifyPixmapHeader_driver(PixmapPtr pPixmap, int width, int height,
|
||||
int depth, int bitsPerPixel, int devKind,
|
||||
void *pPixData);
|
||||
|
||||
Bool
|
||||
exaDestroyPixmap_driver(PixmapPtr pPixmap);
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy_driver(PixmapPtr pPixmap);
|
||||
|
||||
/* exa_mixed.c */
|
||||
PixmapPtr
|
||||
|
||||
exaCreatePixmap_mixed(ScreenPtr pScreen, int w, int h, int depth,
|
||||
unsigned usage_hint);
|
||||
|
||||
Bool
|
||||
|
||||
exaModifyPixmapHeader_mixed(PixmapPtr pPixmap, int width, int height, int depth,
|
||||
int bitsPerPixel, int devKind, void *pPixData);
|
||||
|
||||
Bool
|
||||
exaDestroyPixmap_mixed(PixmapPtr pPixmap);
|
||||
|
||||
Bool
|
||||
exaPixmapHasGpuCopy_mixed(PixmapPtr pPixmap);
|
||||
|
||||
/* exa_migration_mixed.c */
|
||||
void
|
||||
exaCreateDriverPixmap_mixed(PixmapPtr pPixmap);
|
||||
|
||||
void
|
||||
exaDoMigration_mixed(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
|
||||
|
||||
void
|
||||
exaMoveInPixmap_mixed(PixmapPtr pPixmap);
|
||||
|
||||
void
|
||||
exaDamageReport_mixed(DamagePtr pDamage, RegionPtr pRegion, void *closure);
|
||||
|
||||
void
|
||||
exaPrepareAccessReg_mixed(PixmapPtr pPixmap, int index, RegionPtr pReg);
|
||||
|
||||
Bool
|
||||
exaSetSharedPixmapBacking_mixed(PixmapPtr pPixmap, void *handle);
|
||||
Bool
|
||||
exaSharePixmapBacking_mixed(PixmapPtr pPixmap, ScreenPtr secondary, void **handle_p);
|
||||
|
||||
/* exa_render.c */
|
||||
Bool
|
||||
exaOpReadsDestination(CARD8 op);
|
||||
|
||||
void
|
||||
|
||||
exaComposite(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pMask,
|
||||
PicturePtr pDst,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc,
|
||||
INT16 xMask,
|
||||
INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
|
||||
|
||||
void
|
||||
|
||||
exaCompositeRects(CARD8 op,
|
||||
PicturePtr Src,
|
||||
PicturePtr pMask,
|
||||
PicturePtr pDst, int nrect, ExaCompositeRectPtr rects);
|
||||
|
||||
void
|
||||
|
||||
exaTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
|
||||
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
|
||||
int ntrap, xTrapezoid * traps);
|
||||
|
||||
void
|
||||
|
||||
exaTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
|
||||
PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
|
||||
int ntri, xTriangle * tris);
|
||||
|
||||
/* exa_glyph.c */
|
||||
void
|
||||
exaGlyphsInit(ScreenPtr pScreen);
|
||||
|
||||
void
|
||||
exaGlyphsFini(ScreenPtr pScreen);
|
||||
|
||||
void
|
||||
|
||||
exaGlyphs(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pDst,
|
||||
PictFormatPtr maskFormat,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs);
|
||||
|
||||
/* exa_migration_classic.c */
|
||||
void
|
||||
exaCopyDirtyToSys(ExaMigrationPtr migrate);
|
||||
|
||||
void
|
||||
exaCopyDirtyToFb(ExaMigrationPtr migrate);
|
||||
|
||||
void
|
||||
exaDoMigration_classic(ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
|
||||
|
||||
void
|
||||
exaPixmapSave(ScreenPtr pScreen, ExaOffscreenArea * area);
|
||||
|
||||
void
|
||||
exaMoveOutPixmap_classic(PixmapPtr pPixmap);
|
||||
|
||||
void
|
||||
exaMoveInPixmap_classic(PixmapPtr pPixmap);
|
||||
|
||||
void
|
||||
exaPrepareAccessReg_classic(PixmapPtr pPixmap, int index, RegionPtr pReg);
|
||||
|
||||
#endif /* EXAPRIV_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,733 @@
|
|||
/*
|
||||
*
|
||||
* Copyright © 1999 Keith Packard
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of Keith Packard not be used in
|
||||
* advertising or publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. Keith Packard makes no
|
||||
* representations about the suitability of this software for any purpose. It
|
||||
* is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL KEITH PACKARD 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 "exa_priv.h"
|
||||
|
||||
#include "mipict.h"
|
||||
|
||||
/*
|
||||
* These functions wrap the low-level fb rendering functions and
|
||||
* synchronize framebuffer/accelerated drawing by stalling until
|
||||
* the accelerator is idle
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calls exaPrepareAccess with EXA_PREPARE_SRC for the tile, if that is the
|
||||
* current fill style.
|
||||
*
|
||||
* Solid doesn't use an extra pixmap source, and Stippled/OpaqueStippled are
|
||||
* 1bpp and never in fb, so we don't worry about them.
|
||||
* We should worry about them for completeness sake and going forward.
|
||||
*/
|
||||
void
|
||||
exaPrepareAccessGC(GCPtr pGC)
|
||||
{
|
||||
if (pGC->stipple)
|
||||
exaPrepareAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
|
||||
if (pGC->fillStyle == FillTiled)
|
||||
exaPrepareAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes access to the tile in the GC, if used.
|
||||
*/
|
||||
void
|
||||
exaFinishAccessGC(GCPtr pGC)
|
||||
{
|
||||
if (pGC->fillStyle == FillTiled)
|
||||
exaFinishAccess(&pGC->tile.pixmap->drawable, EXA_PREPARE_SRC);
|
||||
if (pGC->stipple)
|
||||
exaFinishAccess(&pGC->stipple->drawable, EXA_PREPARE_MASK);
|
||||
}
|
||||
|
||||
#if DEBUG_TRACE_FALL
|
||||
char
|
||||
exaDrawableLocation(DrawablePtr pDrawable)
|
||||
{
|
||||
return exaDrawableIsOffscreen(pDrawable) ? 's' : 'm';
|
||||
}
|
||||
#endif /* DEBUG_TRACE_FALL */
|
||||
|
||||
void
|
||||
ExaCheckFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nspans,
|
||||
DDXPointPtr ppt, int *pwidth, int fSorted)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->FillSpans(pDrawable, pGC, nspans, ppt, pwidth, fSorted);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
|
||||
DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
pGC->ops->SetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
|
||||
int x, int y, int w, int h, int leftPad, int format,
|
||||
char *bits)
|
||||
{
|
||||
PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
|
||||
|
||||
ExaPixmapPriv(pPixmap);
|
||||
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
if (!pExaScr->prepare_access_reg || !pExaPixmap->pDamage ||
|
||||
exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle,
|
||||
pGC->alu, pGC->clientClip != NULL))
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
else
|
||||
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST,
|
||||
DamagePendingRegion(pExaPixmap->pDamage));
|
||||
pGC->ops->PutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format,
|
||||
bits);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckCopyNtoN(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
|
||||
BoxPtr pbox, int nbox, int dx, int dy, Bool reverse,
|
||||
Bool upsidedown, Pixel bitplane, void *closure)
|
||||
{
|
||||
RegionRec reg;
|
||||
int xoff, yoff;
|
||||
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
|
||||
exaDrawableLocation(pSrc), exaDrawableLocation(pDst)));
|
||||
|
||||
if (pExaScr->prepare_access_reg && RegionInitBoxes(®, pbox, nbox)) {
|
||||
PixmapPtr pPixmap = exaGetDrawablePixmap(pSrc);
|
||||
|
||||
exaGetDrawableDeltas(pSrc, pPixmap, &xoff, &yoff);
|
||||
RegionTranslate(®, xoff + dx, yoff + dy);
|
||||
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, ®);
|
||||
RegionUninit(®);
|
||||
}
|
||||
else
|
||||
exaPrepareAccess(pSrc, EXA_PREPARE_SRC);
|
||||
|
||||
if (pExaScr->prepare_access_reg &&
|
||||
!exaGCReadsDestination(pDst, pGC->planemask, pGC->fillStyle,
|
||||
pGC->alu, pGC->clientClip != NULL) &&
|
||||
RegionInitBoxes(®, pbox, nbox)) {
|
||||
PixmapPtr pPixmap = exaGetDrawablePixmap(pDst);
|
||||
|
||||
exaGetDrawableDeltas(pDst, pPixmap, &xoff, &yoff);
|
||||
RegionTranslate(®, xoff, yoff);
|
||||
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_DEST, ®);
|
||||
RegionUninit(®);
|
||||
}
|
||||
else
|
||||
exaPrepareAccess(pDst, EXA_PREPARE_DEST);
|
||||
|
||||
/* This will eventually call fbCopyNtoN, with some calculation overhead. */
|
||||
while (nbox--) {
|
||||
pGC->ops->CopyArea(pSrc, pDst, pGC, pbox->x1 - pSrc->x + dx,
|
||||
pbox->y1 - pSrc->y + dy, pbox->x2 - pbox->x1,
|
||||
pbox->y2 - pbox->y1, pbox->x1 - pDst->x,
|
||||
pbox->y1 - pDst->y);
|
||||
pbox++;
|
||||
}
|
||||
exaFinishAccess(pSrc, EXA_PREPARE_SRC);
|
||||
exaFinishAccess(pDst, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
static void
|
||||
ExaFallbackPrepareReg(DrawablePtr pDrawable,
|
||||
GCPtr pGC,
|
||||
int x, int y, int width, int height,
|
||||
int index, Bool checkReads)
|
||||
{
|
||||
ScreenPtr pScreen = pDrawable->pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
|
||||
if (pExaScr->prepare_access_reg &&
|
||||
!(checkReads && exaGCReadsDestination(pDrawable, pGC->planemask,
|
||||
pGC->fillStyle, pGC->alu,
|
||||
pGC->clientClip != NULL))) {
|
||||
BoxRec box;
|
||||
RegionRec reg;
|
||||
int xoff, yoff;
|
||||
PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
|
||||
|
||||
exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
|
||||
box.x1 = pDrawable->x + x + xoff;
|
||||
box.y1 = pDrawable->y + y + yoff;
|
||||
box.x2 = box.x1 + width;
|
||||
box.y2 = box.y1 + height;
|
||||
|
||||
RegionInit(®, &box, 1);
|
||||
pExaScr->prepare_access_reg(pPixmap, index, ®);
|
||||
RegionUninit(®);
|
||||
}
|
||||
else
|
||||
exaPrepareAccess(pDrawable, index);
|
||||
}
|
||||
|
||||
RegionPtr
|
||||
ExaCheckCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
|
||||
int srcx, int srcy, int w, int h, int dstx, int dsty)
|
||||
{
|
||||
RegionPtr ret;
|
||||
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
|
||||
exaDrawableLocation(pSrc), exaDrawableLocation(pDst)));
|
||||
ExaFallbackPrepareReg(pSrc, pGC, srcx, srcy, w, h, EXA_PREPARE_SRC, FALSE);
|
||||
ExaFallbackPrepareReg(pDst, pGC, dstx, dsty, w, h, EXA_PREPARE_DEST, TRUE);
|
||||
ret = pGC->ops->CopyArea(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
|
||||
exaFinishAccess(pSrc, EXA_PREPARE_SRC);
|
||||
exaFinishAccess(pDst, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
RegionPtr
|
||||
ExaCheckCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
|
||||
int srcx, int srcy, int w, int h, int dstx, int dsty,
|
||||
unsigned long bitPlane)
|
||||
{
|
||||
RegionPtr ret;
|
||||
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pSrc, pDst,
|
||||
exaDrawableLocation(pSrc), exaDrawableLocation(pDst)));
|
||||
ExaFallbackPrepareReg(pSrc, pGC, srcx, srcy, w, h, EXA_PREPARE_SRC, FALSE);
|
||||
ExaFallbackPrepareReg(pDst, pGC, dstx, dsty, w, h, EXA_PREPARE_DEST, TRUE);
|
||||
ret = pGC->ops->CopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty,
|
||||
bitPlane);
|
||||
exaFinishAccess(pSrc, EXA_PREPARE_SRC);
|
||||
exaFinishAccess(pDst, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt,
|
||||
DDXPointPtr pptInit)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
pGC->ops->PolyPoint(pDrawable, pGC, mode, npt, pptInit);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPolylines(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int mode, int npt, DDXPointPtr ppt)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c), width %d, mode %d, count %d\n",
|
||||
pDrawable, exaDrawableLocation(pDrawable),
|
||||
pGC->lineWidth, mode, npt));
|
||||
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->Polylines(pDrawable, pGC, mode, npt, ppt);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPolySegment(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int nsegInit, xSegment * pSegInit)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c) width %d, count %d\n", pDrawable,
|
||||
exaDrawableLocation(pDrawable), pGC->lineWidth, nsegInit));
|
||||
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->PolySegment(pDrawable, pGC, nsegInit, pSegInit);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc * pArcs)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->PolyArc(pDrawable, pGC, narcs, pArcs);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int nrect, xRectangle *prect)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->PolyFillRect(pDrawable, pGC, nrect, prect);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int x, int y, unsigned int nglyph,
|
||||
CharInfoPtr * ppci, void *pglyphBase)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->ImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
|
||||
int x, int y, unsigned int nglyph,
|
||||
CharInfoPtr * ppci, void *pglyphBase)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("to %p (%c), style %d alu %d\n", pDrawable,
|
||||
exaDrawableLocation(pDrawable), pGC->fillStyle, pGC->alu));
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->PolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckPushPixels(GCPtr pGC, PixmapPtr pBitmap,
|
||||
DrawablePtr pDrawable, int w, int h, int x, int y)
|
||||
{
|
||||
EXA_PRE_FALLBACK_GC(pGC);
|
||||
EXA_FALLBACK(("from %p to %p (%c,%c)\n", pBitmap, pDrawable,
|
||||
exaDrawableLocation(&pBitmap->drawable),
|
||||
exaDrawableLocation(pDrawable)));
|
||||
ExaFallbackPrepareReg(pDrawable, pGC, x, y, w, h, EXA_PREPARE_DEST, TRUE);
|
||||
ExaFallbackPrepareReg(&pBitmap->drawable, pGC, 0, 0, w, h,
|
||||
EXA_PREPARE_SRC, FALSE);
|
||||
exaPrepareAccessGC(pGC);
|
||||
pGC->ops->PushPixels(pGC, pBitmap, pDrawable, w, h, x, y);
|
||||
exaFinishAccessGC(pGC);
|
||||
exaFinishAccess(&pBitmap->drawable, EXA_PREPARE_SRC);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK_GC(pGC);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
|
||||
{
|
||||
DrawablePtr pDrawable = &pWin->drawable;
|
||||
ScreenPtr pScreen = pDrawable->pScreen;
|
||||
|
||||
EXA_PRE_FALLBACK(pScreen);
|
||||
EXA_FALLBACK(("from %p\n", pWin));
|
||||
|
||||
/* Only need the source bits, the destination region will be overwritten */
|
||||
if (pExaScr->prepare_access_reg) {
|
||||
PixmapPtr pPixmap = pScreen->GetWindowPixmap(pWin);
|
||||
int xoff, yoff;
|
||||
|
||||
exaGetDrawableDeltas(&pWin->drawable, pPixmap, &xoff, &yoff);
|
||||
RegionTranslate(prgnSrc, xoff, yoff);
|
||||
pExaScr->prepare_access_reg(pPixmap, EXA_PREPARE_SRC, prgnSrc);
|
||||
RegionTranslate(prgnSrc, -xoff, -yoff);
|
||||
}
|
||||
else
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_SRC);
|
||||
|
||||
swap(pExaScr, pScreen, CopyWindow);
|
||||
pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc);
|
||||
swap(pExaScr, pScreen, CopyWindow);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_SRC);
|
||||
EXA_POST_FALLBACK(pScreen);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckGetImage(DrawablePtr pDrawable, int x, int y, int w, int h,
|
||||
unsigned int format, unsigned long planeMask, char *d)
|
||||
{
|
||||
ScreenPtr pScreen = pDrawable->pScreen;
|
||||
|
||||
EXA_PRE_FALLBACK(pScreen);
|
||||
EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
|
||||
ExaFallbackPrepareReg(pDrawable, NULL, x, y, w, h, EXA_PREPARE_SRC, FALSE);
|
||||
swap(pExaScr, pScreen, GetImage);
|
||||
pScreen->GetImage(pDrawable, x, y, w, h, format, planeMask, d);
|
||||
swap(pExaScr, pScreen, GetImage);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_SRC);
|
||||
EXA_POST_FALLBACK(pScreen);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckGetSpans(DrawablePtr pDrawable,
|
||||
int wMax,
|
||||
DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart)
|
||||
{
|
||||
ScreenPtr pScreen = pDrawable->pScreen;
|
||||
|
||||
EXA_PRE_FALLBACK(pScreen);
|
||||
EXA_FALLBACK(("from %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
|
||||
exaPrepareAccess(pDrawable, EXA_PREPARE_SRC);
|
||||
swap(pExaScr, pScreen, GetSpans);
|
||||
pScreen->GetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
|
||||
swap(pExaScr, pScreen, GetSpans);
|
||||
exaFinishAccess(pDrawable, EXA_PREPARE_SRC);
|
||||
EXA_POST_FALLBACK(pScreen);
|
||||
}
|
||||
|
||||
static void
|
||||
ExaSrcValidate(DrawablePtr pDrawable,
|
||||
int x, int y, int width, int height, unsigned int subWindowMode)
|
||||
{
|
||||
ScreenPtr pScreen = pDrawable->pScreen;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
PixmapPtr pPix = exaGetDrawablePixmap(pDrawable);
|
||||
BoxRec box;
|
||||
RegionRec reg;
|
||||
RegionPtr dst;
|
||||
int xoff, yoff;
|
||||
|
||||
if (pExaScr->srcPix == pPix)
|
||||
dst = &pExaScr->srcReg;
|
||||
else if (pExaScr->maskPix == pPix)
|
||||
dst = &pExaScr->maskReg;
|
||||
else
|
||||
return;
|
||||
|
||||
exaGetDrawableDeltas(pDrawable, pPix, &xoff, &yoff);
|
||||
|
||||
box.x1 = x + xoff;
|
||||
box.y1 = y + yoff;
|
||||
box.x2 = box.x1 + width;
|
||||
box.y2 = box.y1 + height;
|
||||
|
||||
RegionInit(®, &box, 1);
|
||||
RegionUnion(dst, dst, ®);
|
||||
RegionUninit(®);
|
||||
|
||||
swap(pExaScr, pScreen, SourceValidate);
|
||||
pScreen->SourceValidate(pDrawable, x, y, width, height, subWindowMode);
|
||||
swap(pExaScr, pScreen, SourceValidate);
|
||||
}
|
||||
|
||||
static Bool
|
||||
ExaPrepareCompositeReg(ScreenPtr pScreen,
|
||||
CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pMask,
|
||||
PicturePtr pDst,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc,
|
||||
INT16 xMask,
|
||||
INT16 yMask,
|
||||
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
|
||||
{
|
||||
RegionRec region;
|
||||
RegionPtr dstReg = NULL;
|
||||
RegionPtr srcReg = NULL;
|
||||
RegionPtr maskReg = NULL;
|
||||
PixmapPtr pSrcPix = NULL;
|
||||
PixmapPtr pMaskPix = NULL;
|
||||
PixmapPtr pDstPix;
|
||||
|
||||
ExaScreenPriv(pScreen);
|
||||
Bool ret;
|
||||
|
||||
RegionNull(®ion);
|
||||
|
||||
if (pSrc->pDrawable) {
|
||||
pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
|
||||
RegionNull(&pExaScr->srcReg);
|
||||
srcReg = &pExaScr->srcReg;
|
||||
pExaScr->srcPix = pSrcPix;
|
||||
if (pSrc != pDst)
|
||||
RegionTranslate(pSrc->pCompositeClip,
|
||||
-pSrc->pDrawable->x, -pSrc->pDrawable->y);
|
||||
} else
|
||||
pExaScr->srcPix = NULL;
|
||||
|
||||
if (pMask && pMask->pDrawable) {
|
||||
pMaskPix = exaGetDrawablePixmap(pMask->pDrawable);
|
||||
RegionNull(&pExaScr->maskReg);
|
||||
maskReg = &pExaScr->maskReg;
|
||||
pExaScr->maskPix = pMaskPix;
|
||||
if (pMask != pDst && pMask != pSrc)
|
||||
RegionTranslate(pMask->pCompositeClip,
|
||||
-pMask->pDrawable->x, -pMask->pDrawable->y);
|
||||
} else
|
||||
pExaScr->maskPix = NULL;
|
||||
|
||||
RegionTranslate(pDst->pCompositeClip,
|
||||
-pDst->pDrawable->x, -pDst->pDrawable->y);
|
||||
|
||||
pExaScr->SavedSourceValidate = ExaSrcValidate;
|
||||
swap(pExaScr, pScreen, SourceValidate);
|
||||
ret = miComputeCompositeRegion(®ion, pSrc, pMask, pDst,
|
||||
xSrc, ySrc, xMask, yMask,
|
||||
xDst, yDst, width, height);
|
||||
swap(pExaScr, pScreen, SourceValidate);
|
||||
|
||||
RegionTranslate(pDst->pCompositeClip,
|
||||
pDst->pDrawable->x, pDst->pDrawable->y);
|
||||
if (pSrc->pDrawable && pSrc != pDst)
|
||||
RegionTranslate(pSrc->pCompositeClip,
|
||||
pSrc->pDrawable->x, pSrc->pDrawable->y);
|
||||
if (pMask && pMask->pDrawable && pMask != pDst && pMask != pSrc)
|
||||
RegionTranslate(pMask->pCompositeClip,
|
||||
pMask->pDrawable->x, pMask->pDrawable->y);
|
||||
|
||||
if (!ret) {
|
||||
if (srcReg)
|
||||
RegionUninit(srcReg);
|
||||
if (maskReg)
|
||||
RegionUninit(maskReg);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't limit alphamaps readbacks for now until we've figured out how that
|
||||
* should be done.
|
||||
*/
|
||||
|
||||
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
|
||||
pExaScr->
|
||||
prepare_access_reg(exaGetDrawablePixmap(pSrc->alphaMap->pDrawable),
|
||||
EXA_PREPARE_AUX_SRC, NULL);
|
||||
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
|
||||
pExaScr->
|
||||
prepare_access_reg(exaGetDrawablePixmap(pMask->alphaMap->pDrawable),
|
||||
EXA_PREPARE_AUX_MASK, NULL);
|
||||
|
||||
if (pSrcPix)
|
||||
pExaScr->prepare_access_reg(pSrcPix, EXA_PREPARE_SRC, srcReg);
|
||||
|
||||
if (pMaskPix)
|
||||
pExaScr->prepare_access_reg(pMaskPix, EXA_PREPARE_MASK, maskReg);
|
||||
|
||||
if (srcReg)
|
||||
RegionUninit(srcReg);
|
||||
if (maskReg)
|
||||
RegionUninit(maskReg);
|
||||
|
||||
pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
|
||||
if (!exaOpReadsDestination(op)) {
|
||||
int xoff;
|
||||
int yoff;
|
||||
|
||||
exaGetDrawableDeltas(pDst->pDrawable, pDstPix, &xoff, &yoff);
|
||||
RegionTranslate(®ion, pDst->pDrawable->x + xoff,
|
||||
pDst->pDrawable->y + yoff);
|
||||
dstReg = ®ion;
|
||||
}
|
||||
|
||||
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
|
||||
pExaScr->
|
||||
prepare_access_reg(exaGetDrawablePixmap(pDst->alphaMap->pDrawable),
|
||||
EXA_PREPARE_AUX_DEST, dstReg);
|
||||
pExaScr->prepare_access_reg(pDstPix, EXA_PREPARE_DEST, dstReg);
|
||||
|
||||
RegionUninit(®ion);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckComposite(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pMask,
|
||||
PicturePtr pDst,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc,
|
||||
INT16 xMask,
|
||||
INT16 yMask,
|
||||
INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
|
||||
{
|
||||
ScreenPtr pScreen = pDst->pDrawable->pScreen;
|
||||
PictureScreenPtr ps = GetPictureScreen(pScreen);
|
||||
|
||||
EXA_PRE_FALLBACK(pScreen);
|
||||
|
||||
if (pExaScr->prepare_access_reg) {
|
||||
if (!ExaPrepareCompositeReg(pScreen, op, pSrc, pMask, pDst, xSrc,
|
||||
ySrc, xMask, yMask, xDst, yDst, width,
|
||||
height))
|
||||
goto out_no_clip;
|
||||
}
|
||||
else {
|
||||
|
||||
/* We need to prepare access to any separate alpha maps first,
|
||||
* in case the driver doesn't support EXA_PREPARE_AUX*,
|
||||
* in which case EXA_PREPARE_SRC may be used for moving them out.
|
||||
*/
|
||||
|
||||
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
|
||||
exaPrepareAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC);
|
||||
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
|
||||
exaPrepareAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK);
|
||||
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
|
||||
exaPrepareAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST);
|
||||
|
||||
exaPrepareAccess(pDst->pDrawable, EXA_PREPARE_DEST);
|
||||
|
||||
EXA_FALLBACK(("from picts %p/%p to pict %p\n", pSrc, pMask, pDst));
|
||||
|
||||
if (pSrc->pDrawable != NULL)
|
||||
exaPrepareAccess(pSrc->pDrawable, EXA_PREPARE_SRC);
|
||||
if (pMask && pMask->pDrawable != NULL)
|
||||
exaPrepareAccess(pMask->pDrawable, EXA_PREPARE_MASK);
|
||||
}
|
||||
|
||||
swap(pExaScr, ps, Composite);
|
||||
ps->Composite(op,
|
||||
pSrc,
|
||||
pMask,
|
||||
pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height);
|
||||
swap(pExaScr, ps, Composite);
|
||||
if (pMask && pMask->pDrawable != NULL)
|
||||
exaFinishAccess(pMask->pDrawable, EXA_PREPARE_MASK);
|
||||
if (pSrc->pDrawable != NULL)
|
||||
exaFinishAccess(pSrc->pDrawable, EXA_PREPARE_SRC);
|
||||
exaFinishAccess(pDst->pDrawable, EXA_PREPARE_DEST);
|
||||
if (pDst->alphaMap && pDst->alphaMap->pDrawable)
|
||||
exaFinishAccess(pDst->alphaMap->pDrawable, EXA_PREPARE_AUX_DEST);
|
||||
if (pSrc->alphaMap && pSrc->alphaMap->pDrawable)
|
||||
exaFinishAccess(pSrc->alphaMap->pDrawable, EXA_PREPARE_AUX_SRC);
|
||||
if (pMask && pMask->alphaMap && pMask->alphaMap->pDrawable)
|
||||
exaFinishAccess(pMask->alphaMap->pDrawable, EXA_PREPARE_AUX_MASK);
|
||||
|
||||
out_no_clip:
|
||||
EXA_POST_FALLBACK(pScreen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid migration ping-pong when using a mask.
|
||||
*/
|
||||
void
|
||||
ExaCheckGlyphs(CARD8 op,
|
||||
PicturePtr pSrc,
|
||||
PicturePtr pDst,
|
||||
PictFormatPtr maskFormat,
|
||||
INT16 xSrc,
|
||||
INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
|
||||
{
|
||||
ScreenPtr pScreen = pDst->pDrawable->pScreen;
|
||||
|
||||
EXA_PRE_FALLBACK(pScreen);
|
||||
|
||||
miGlyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
|
||||
|
||||
EXA_POST_FALLBACK(pScreen);
|
||||
}
|
||||
|
||||
void
|
||||
ExaCheckAddTraps(PicturePtr pPicture,
|
||||
INT16 x_off, INT16 y_off, int ntrap, xTrap * traps)
|
||||
{
|
||||
ScreenPtr pScreen = pPicture->pDrawable->pScreen;
|
||||
PictureScreenPtr ps = GetPictureScreen(pScreen);
|
||||
|
||||
EXA_PRE_FALLBACK(pScreen);
|
||||
|
||||
EXA_FALLBACK(("to pict %p (%c)\n", pPicture,
|
||||
exaDrawableLocation(pPicture->pDrawable)));
|
||||
exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
|
||||
swap(pExaScr, ps, AddTraps);
|
||||
ps->AddTraps(pPicture, x_off, y_off, ntrap, traps);
|
||||
swap(pExaScr, ps, AddTraps);
|
||||
exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
|
||||
EXA_POST_FALLBACK(pScreen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 0,0 pixel of a pixmap. Used for doing solid fills of tiled pixmaps
|
||||
* that happen to be 1x1. Pixmap must be at least 8bpp.
|
||||
*/
|
||||
CARD32
|
||||
exaGetPixmapFirstPixel(PixmapPtr pPixmap)
|
||||
{
|
||||
switch (pPixmap->drawable.bitsPerPixel) {
|
||||
case 32:
|
||||
{
|
||||
CARD32 pixel;
|
||||
|
||||
pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1,
|
||||
ZPixmap, ~0, (char *) &pixel);
|
||||
return pixel;
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
CARD16 pixel;
|
||||
|
||||
pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1,
|
||||
ZPixmap, ~0, (char *) &pixel);
|
||||
return pixel;
|
||||
}
|
||||
case 8:
|
||||
case 4:
|
||||
case 1:
|
||||
{
|
||||
CARD8 pixel;
|
||||
|
||||
pPixmap->drawable.pScreen->GetImage(&pPixmap->drawable, 0, 0, 1, 1,
|
||||
ZPixmap, ~0, (char *) &pixel);
|
||||
return pixel;
|
||||
}
|
||||
default:
|
||||
FatalError("%s called for invalid bpp %d\n", __func__,
|
||||
pPixmap->drawable.bitsPerPixel);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
srcs_exa = [
|
||||
'exa.c',
|
||||
'exa_classic.c',
|
||||
'exa_migration_classic.c',
|
||||
'exa_driver.c',
|
||||
'exa_mixed.c',
|
||||
'exa_migration_mixed.c',
|
||||
'exa_accel.c',
|
||||
'exa_glyphs.c',
|
||||
'exa_offscreen.c',
|
||||
'exa_render.c',
|
||||
'exa_unaccel.c',
|
||||
]
|
||||
|
||||
libxserver_exa = static_library('libxserver_exa',
|
||||
srcs_exa,
|
||||
include_directories: inc,
|
||||
dependencies: common_dep,
|
||||
c_args: '-DHAVE_XORG_CONFIG_H'
|
||||
)
|
||||
|
||||
if build_xorg
|
||||
install_data('exa.h', install_dir: xorgsdkdir)
|
||||
endif
|
|
@ -0,0 +1,49 @@
|
|||
noinst_LTLIBRARIES = libfb.la libwfb.la
|
||||
|
||||
AM_CFLAGS = $(DIX_CFLAGS)
|
||||
|
||||
if XORG
|
||||
sdk_HEADERS = fb.h fbrop.h fboverlay.h wfbrename.h fbpict.h
|
||||
endif
|
||||
|
||||
libfb_la_CFLAGS = $(AM_CFLAGS)
|
||||
libfb_la_LIBADD = $(PIXMAN_LIBS)
|
||||
|
||||
libwfb_la_CFLAGS = $(AM_CFLAGS) -DFB_ACCESS_WRAPPER
|
||||
libwfb_la_LIBADD = $(PIXMAN_LIBS)
|
||||
|
||||
libfb_la_SOURCES = \
|
||||
fb.h \
|
||||
fballpriv.c \
|
||||
fbarc.c \
|
||||
fbbits.c \
|
||||
fbbits.h \
|
||||
fbblt.c \
|
||||
fbbltone.c \
|
||||
fbcmap_mi.c \
|
||||
fbcopy.c \
|
||||
fbfill.c \
|
||||
fbfillrect.c \
|
||||
fbfillsp.c \
|
||||
fbgc.c \
|
||||
fbgetsp.c \
|
||||
fbglyph.c \
|
||||
fbimage.c \
|
||||
fbline.c \
|
||||
fboverlay.c \
|
||||
fboverlay.h \
|
||||
fbpict.c \
|
||||
fbpict.h \
|
||||
fbpixmap.c \
|
||||
fbpoint.c \
|
||||
fbpush.c \
|
||||
fbrop.h \
|
||||
fbscreen.c \
|
||||
fbseg.c \
|
||||
fbsetsp.c \
|
||||
fbsolid.c \
|
||||
fbtrap.c \
|
||||
fbutil.c \
|
||||
fbwindow.c
|
||||
|
||||
libwfb_la_SOURCES = $(libfb_la_SOURCES)
|
|
@ -53,3 +53,7 @@ libxserver_wfb = static_library('libxserver_wfb',
|
|||
pic: true,
|
||||
build_by_default: false,
|
||||
)
|
||||
|
||||
if build_xorg
|
||||
install_data(hdrs_fb, install_dir: xorgsdkdir)
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
noinst_LTLIBRARIES = libglamor.la libglamor_egl_stubs.la
|
||||
|
||||
libglamor_la_LIBADD = $(GLAMOR_LIBS)
|
||||
|
||||
AM_CFLAGS = $(CWARNFLAGS) $(DIX_CFLAGS) $(GLAMOR_CFLAGS)
|
||||
|
||||
libglamor_la_SOURCES = \
|
||||
glamor.c \
|
||||
glamor_context.h \
|
||||
glamor_copy.c \
|
||||
glamor_core.c \
|
||||
glamor_dash.c \
|
||||
glamor_debug.h \
|
||||
glamor_font.c \
|
||||
glamor_font.h \
|
||||
glamor_glx.c \
|
||||
glamor_composite_glyphs.c \
|
||||
glamor_image.c \
|
||||
glamor_lines.c \
|
||||
glamor_segs.c \
|
||||
glamor_render.c \
|
||||
glamor_gradient.c \
|
||||
glamor_prepare.c \
|
||||
glamor_prepare.h \
|
||||
glamor_program.c \
|
||||
glamor_program.h \
|
||||
glamor_rects.c \
|
||||
glamor_spans.c \
|
||||
glamor_text.c \
|
||||
glamor_transfer.c \
|
||||
glamor_transfer.h \
|
||||
glamor_transform.c \
|
||||
glamor_transform.h \
|
||||
glamor_trapezoid.c \
|
||||
glamor_triangles.c\
|
||||
glamor_addtraps.c\
|
||||
glamor_glyphblt.c\
|
||||
glamor_points.c\
|
||||
glamor_priv.h\
|
||||
glamor_pixmap.c\
|
||||
glamor_largepixmap.c\
|
||||
glamor_picture.c\
|
||||
glamor_vbo.c \
|
||||
glamor_window.c\
|
||||
glamor_fbo.c\
|
||||
glamor_compositerects.c\
|
||||
glamor_utils.c\
|
||||
glamor_utils.h\
|
||||
glamor_sync.c \
|
||||
glamor.h
|
||||
|
||||
if XV
|
||||
libglamor_la_SOURCES += \
|
||||
glamor_xv.c
|
||||
endif
|
||||
|
||||
libglamor_egl_stubs_la_SOURCES = \
|
||||
glamor_egl_stubs.c \
|
||||
glamor_egl_ext.h \
|
||||
glamor_egl.h
|
||||
|
||||
sdk_HEADERS = glamor.h
|
|
@ -746,7 +746,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
|
|||
* have instanced arrays, but this is not always the case.
|
||||
* etnaviv offers GLSL 140 with OpenGL 2.1.
|
||||
*/
|
||||
if (glamor_priv->glsl_version >= 130 &&
|
||||
if (glamor_glsl_has_ints(glamor_priv) &&
|
||||
!epoxy_has_gl_extension("GL_ARB_instanced_arrays"))
|
||||
glamor_priv->glsl_version = 120;
|
||||
} else {
|
||||
|
@ -772,6 +772,10 @@ glamor_init(ScreenPtr screen, unsigned int flags)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (!glamor_priv->is_gles && glamor_priv->glsl_version == 120 &&
|
||||
epoxy_has_gl_extension("GL_ARB_instanced_arrays"))
|
||||
glamor_priv->use_gpu_shader4 = epoxy_has_gl_extension("GL_EXT_gpu_shader4");
|
||||
|
||||
glamor_priv->has_rw_pbo = FALSE;
|
||||
if (!glamor_priv->is_gles)
|
||||
glamor_priv->has_rw_pbo = TRUE;
|
||||
|
@ -799,7 +803,7 @@ glamor_init(ScreenPtr screen, unsigned int flags)
|
|||
epoxy_gl_version() >= 30 ||
|
||||
epoxy_has_gl_extension("GL_NV_pack_subimage");
|
||||
glamor_priv->has_dual_blend =
|
||||
glamor_priv->glsl_version >= 130 &&
|
||||
glamor_glsl_has_ints(glamor_priv) &&
|
||||
epoxy_has_gl_extension("GL_ARB_blend_func_extended");
|
||||
glamor_priv->has_clear_texture =
|
||||
epoxy_gl_version() >= 44 ||
|
||||
|
@ -817,7 +821,8 @@ glamor_init(ScreenPtr screen, unsigned int flags)
|
|||
* cached IB.
|
||||
*/
|
||||
if (strstr((char *)glGetString(GL_VENDOR), "Broadcom") &&
|
||||
strstr((char *)glGetString(GL_RENDERER), "VC4"))
|
||||
(strstr((char *)glGetString(GL_RENDERER), "VC4") ||
|
||||
strstr((char *)glGetString(GL_RENDERER), "V3D")))
|
||||
glamor_priv->use_quads = FALSE;
|
||||
|
||||
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glamor_priv->max_fbo_size);
|
||||
|
|
|
@ -208,11 +208,6 @@ static const glamor_facet glamor_facet_composite_glyphs_120 = {
|
|||
.locations = glamor_program_location_atlas,
|
||||
};
|
||||
|
||||
static inline Bool
|
||||
glamor_glyph_use_130(glamor_screen_private *glamor_priv) {
|
||||
return glamor_priv->glsl_version >= 130;
|
||||
}
|
||||
|
||||
static Bool
|
||||
glamor_glyphs_init_facet(ScreenPtr screen)
|
||||
{
|
||||
|
@ -274,7 +269,7 @@ glamor_glyphs_flush(CARD8 op, PicturePtr src, PicturePtr dst,
|
|||
box->y2 - box->y1);
|
||||
box++;
|
||||
|
||||
if (glamor_glyph_use_130(glamor_priv))
|
||||
if (glamor_glsl_has_ints(glamor_priv))
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nglyph);
|
||||
else
|
||||
glamor_glDrawArrays_GL_QUADS(glamor_priv, nglyph);
|
||||
|
@ -287,7 +282,7 @@ glamor_glyphs_flush(CARD8 op, PicturePtr src, PicturePtr dst,
|
|||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
if (glamor_glyph_use_130(glamor_priv)) {
|
||||
if (glamor_glsl_has_ints(glamor_priv)) {
|
||||
glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0);
|
||||
glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);
|
||||
}
|
||||
|
@ -305,7 +300,7 @@ glamor_glyph_start(ScreenPtr screen, int count)
|
|||
|
||||
/* Set up the vertex buffers for the font and destination */
|
||||
|
||||
if (glamor_glyph_use_130(glamor_priv)) {
|
||||
if (glamor_glsl_has_ints(glamor_priv)) {
|
||||
v = glamor_get_vbo_space(screen, count * (6 * sizeof (GLshort)), &vbo_offset);
|
||||
|
||||
glEnableVertexAttribArray(GLAMOR_VERTEX_POS);
|
||||
|
@ -439,7 +434,7 @@ glamor_composite_glyphs(CARD8 op,
|
|||
/* First glyph in the current atlas?
|
||||
*/
|
||||
if (_X_UNLIKELY(glyphs_queued == 0)) {
|
||||
if (glamor_glyph_use_130(glamor_priv))
|
||||
if (glamor_glsl_has_ints(glamor_priv))
|
||||
prog = glamor_setup_program_render(op, src, glyph_pict, dst,
|
||||
glyphs_program,
|
||||
&glamor_facet_composite_glyphs_130,
|
||||
|
@ -458,7 +453,7 @@ glamor_composite_glyphs(CARD8 op,
|
|||
*/
|
||||
|
||||
glyphs_queued++;
|
||||
if (_X_LIKELY(glamor_glyph_use_130(glamor_priv))) {
|
||||
if (_X_LIKELY(glamor_glsl_has_ints(glamor_priv))) {
|
||||
v[0] = x - glyph->info.x;
|
||||
v[1] = y - glyph->info.y;
|
||||
v[2] = glyph_draw->width;
|
||||
|
|
|
@ -1060,9 +1060,14 @@ glamor_egl_init(ScrnInfoPtr scrn, int fd)
|
|||
goto error;
|
||||
}
|
||||
if (strstr((const char *)renderer, "llvmpipe")) {
|
||||
xf86DrvMsg(scrn->scrnIndex, X_INFO,
|
||||
"Refusing to try glamor on llvmpipe\n");
|
||||
goto error;
|
||||
if (scrn->confScreen->num_gpu_devices)
|
||||
xf86DrvMsg(scrn->scrnIndex, X_INFO,
|
||||
"Allowing glamor on llvmpipe for PRIME\n");
|
||||
else {
|
||||
xf86DrvMsg(scrn->scrnIndex, X_INFO,
|
||||
"Refusing to try glamor on llvmpipe\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -47,7 +47,7 @@ glamor_font_get(ScreenPtr screen, FontPtr font)
|
|||
unsigned long count;
|
||||
char *bits;
|
||||
|
||||
if (glamor_priv->glsl_version < 130)
|
||||
if (!glamor_glsl_has_ints(glamor_priv))
|
||||
return NULL;
|
||||
|
||||
privates = FontGetPrivate(font, glamor_font_private_index);
|
||||
|
@ -210,7 +210,7 @@ glamor_font_init(ScreenPtr screen)
|
|||
{
|
||||
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
|
||||
|
||||
if (glamor_priv->glsl_version < 130)
|
||||
if (!glamor_glsl_has_ints(glamor_priv))
|
||||
return TRUE;
|
||||
|
||||
if (glamor_font_generation != serverGeneration) {
|
||||
|
|
|
@ -213,6 +213,7 @@ typedef struct glamor_screen_private {
|
|||
Bool has_texture_swizzle;
|
||||
Bool is_core_profile;
|
||||
Bool can_copyplane;
|
||||
Bool use_gpu_shader4;
|
||||
int max_fbo_size;
|
||||
|
||||
struct glamor_format formats[33];
|
||||
|
|
|
@ -187,6 +187,7 @@ fs_location_vars(glamor_program_location locations)
|
|||
|
||||
static const char vs_template[] =
|
||||
"%s" /* version */
|
||||
"%s" /* exts */
|
||||
"%s" /* defines */
|
||||
"%s" /* prim vs_vars */
|
||||
"%s" /* fill vs_vars */
|
||||
|
@ -199,6 +200,7 @@ static const char vs_template[] =
|
|||
|
||||
static const char fs_template[] =
|
||||
"%s" /* version */
|
||||
"%s" /* exts */
|
||||
GLAMOR_DEFAULT_PRECISION
|
||||
"%s" /* defines */
|
||||
"%s" /* prim fs_vars */
|
||||
|
@ -262,6 +264,7 @@ glamor_build_program(ScreenPtr screen,
|
|||
char *fs_prog_string;
|
||||
|
||||
GLint fs_prog, vs_prog;
|
||||
Bool gpu_shader4 = FALSE;
|
||||
|
||||
if (!fill)
|
||||
fill = &facet_null_fill;
|
||||
|
@ -270,8 +273,14 @@ glamor_build_program(ScreenPtr screen,
|
|||
flags |= fill->flags;
|
||||
version = MAX(version, fill->version);
|
||||
|
||||
if (version > glamor_priv->glsl_version)
|
||||
goto fail;
|
||||
if (version > glamor_priv->glsl_version) {
|
||||
if (version == 130 && !glamor_priv->use_gpu_shader4)
|
||||
goto fail;
|
||||
else {
|
||||
version = 120;
|
||||
gpu_shader4 = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
vs_vars = vs_location_vars(locations);
|
||||
fs_vars = fs_location_vars(locations);
|
||||
|
@ -291,6 +300,7 @@ glamor_build_program(ScreenPtr screen,
|
|||
if (asprintf(&vs_prog_string,
|
||||
vs_template,
|
||||
str(version_string),
|
||||
gpu_shader4 ? "#extension GL_EXT_gpu_shader4 : require\n" : "",
|
||||
str(defines),
|
||||
str(prim->vs_vars),
|
||||
str(fill->vs_vars),
|
||||
|
@ -302,6 +312,7 @@ glamor_build_program(ScreenPtr screen,
|
|||
if (asprintf(&fs_prog_string,
|
||||
fs_template,
|
||||
str(version_string),
|
||||
gpu_shader4 ? "#extension GL_EXT_gpu_shader4 : require\n#define texelFetch texelFetch2D\n#define uint unsigned int\n" : "",
|
||||
str(defines),
|
||||
str(prim->fs_vars),
|
||||
str(fill->fs_vars),
|
||||
|
|
|
@ -69,7 +69,7 @@ glamor_poly_fill_rect_gl(DrawablePtr drawable,
|
|||
glamor_bounds_union_rect(&bounds, &prect[i]);
|
||||
}
|
||||
|
||||
if (glamor_priv->glsl_version >= 130) {
|
||||
if (glamor_glsl_has_ints(glamor_priv)) {
|
||||
prog = glamor_use_program_fill(pixmap, gc,
|
||||
&glamor_priv->poly_fill_rect_program,
|
||||
&glamor_facet_polyfillrect_130);
|
||||
|
@ -151,7 +151,7 @@ glamor_poly_fill_rect_gl(DrawablePtr drawable,
|
|||
scissor.y1 + off_y,
|
||||
scissor.x2 - scissor.x1,
|
||||
scissor.y2 - scissor.y1);
|
||||
if (glamor_priv->glsl_version >= 130)
|
||||
if (glamor_glsl_has_ints(glamor_priv))
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, nrect);
|
||||
else {
|
||||
glamor_glDrawArrays_GL_QUADS(glamor_priv, nrect);
|
||||
|
@ -163,7 +163,7 @@ glamor_poly_fill_rect_gl(DrawablePtr drawable,
|
|||
|
||||
bail:
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
if (glamor_priv->glsl_version >= 130) {
|
||||
if (glamor_glsl_has_ints(glamor_priv)) {
|
||||
glVertexAttribDivisor(GLAMOR_VERTEX_SOURCE, 0);
|
||||
glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE);
|
||||
glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);
|
||||
|
|
|
@ -560,8 +560,8 @@ glamor_set_composite_texture(glamor_screen_private *glamor_priv, int unit,
|
|||
case PictFilterGood:
|
||||
case PictFilterBest:
|
||||
case PictFilterBilinear:
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ glamor_fill_spans_gl(DrawablePtr drawable,
|
|||
|
||||
glamor_make_current(glamor_priv);
|
||||
|
||||
if (glamor_priv->glsl_version >= 130) {
|
||||
if (glamor_glsl_has_ints(glamor_priv)) {
|
||||
prog = glamor_use_program_fill(pixmap, gc, &glamor_priv->fill_spans_program,
|
||||
&glamor_facet_fillspans_130);
|
||||
|
||||
|
@ -134,7 +134,7 @@ glamor_fill_spans_gl(DrawablePtr drawable,
|
|||
box->x2 - box->x1,
|
||||
box->y2 - box->y1);
|
||||
box++;
|
||||
if (glamor_priv->glsl_version >= 130)
|
||||
if (glamor_glsl_has_ints(glamor_priv))
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, n);
|
||||
else {
|
||||
glamor_glDrawArrays_GL_QUADS(glamor_priv, n);
|
||||
|
@ -146,7 +146,7 @@ glamor_fill_spans_gl(DrawablePtr drawable,
|
|||
|
||||
bail:
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
if (glamor_priv->glsl_version >= 130)
|
||||
if (glamor_glsl_has_ints(glamor_priv))
|
||||
glVertexAttribDivisor(GLAMOR_VERTEX_POS, 0);
|
||||
glDisableVertexAttribArray(GLAMOR_VERTEX_POS);
|
||||
|
||||
|
|
|
@ -732,5 +732,9 @@ glamor_glDrawArrays_GL_QUADS(glamor_screen_private *glamor_priv, unsigned count)
|
|||
}
|
||||
}
|
||||
|
||||
static inline Bool
|
||||
glamor_glsl_has_ints(glamor_screen_private *glamor_priv) {
|
||||
return glamor_priv->glsl_version >= 130 || glamor_priv->use_gpu_shader4;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -380,15 +380,15 @@ glamor_xv_render(glamor_port_private *port_priv, int id)
|
|||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[0]->fbo->tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[1]->fbo->tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
|
@ -397,8 +397,8 @@ glamor_xv_render(glamor_port_private *port_priv, int id)
|
|||
case FOURCC_I420:
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, src_pixmap_priv[2]->fbo->tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
break;
|
||||
|
|
|
@ -54,3 +54,7 @@ glamor_egl_stubs = static_library('glamor_egl_stubs',
|
|||
include_directories: inc,
|
||||
dependencies: common_dep,
|
||||
)
|
||||
|
||||
if build_xorg
|
||||
install_data('glamor.h', install_dir: xorgsdkdir)
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
if DRI2
|
||||
GLXDRI_LIBRARY = libglxdri.la
|
||||
endif
|
||||
|
||||
noinst_LTLIBRARIES = libglx.la $(GLXDRI_LIBRARY) libglxvnd.la
|
||||
|
||||
AM_CFLAGS = \
|
||||
@DIX_CFLAGS@ \
|
||||
@GL_CFLAGS@ \
|
||||
@XLIB_CFLAGS@ \
|
||||
@LIBDRM_CFLAGS@ \
|
||||
@GLX_DEFINES@ \
|
||||
@GLX_ARCH_DEFINES@
|
||||
|
||||
sdk_HEADERS = vndserver.h
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/hw/xfree86/os-support \
|
||||
-I$(top_srcdir)/hw/xfree86/os-support/bus \
|
||||
-I$(top_srcdir)/hw/xfree86/common \
|
||||
-I$(top_srcdir)/hw/xfree86/dri \
|
||||
-I$(top_srcdir)/hw/xfree86/dri2 \
|
||||
-I$(top_srcdir)/mi \
|
||||
-I$(top_srcdir)/present
|
||||
|
||||
indirect_sources = \
|
||||
indirect_dispatch.c \
|
||||
indirect_dispatch.h \
|
||||
indirect_dispatch_swap.c \
|
||||
indirect_reqsize.c \
|
||||
indirect_reqsize.h \
|
||||
indirect_size.h \
|
||||
indirect_size_get.c \
|
||||
indirect_size_get.h \
|
||||
indirect_table.c
|
||||
|
||||
libglxdri_la_SOURCES =
|
||||
if DRI2
|
||||
libglxdri_la_SOURCES += glxdri2.c
|
||||
endif
|
||||
|
||||
libglxdri_la_LIBADD = $(DLOPEN_LIBS)
|
||||
|
||||
libglx_la_SOURCES = \
|
||||
$(indirect_sources) \
|
||||
clientinfo.c \
|
||||
createcontext.c \
|
||||
extension_string.c \
|
||||
extension_string.h \
|
||||
indirect_util.c \
|
||||
indirect_util.h \
|
||||
indirect_program.c \
|
||||
indirect_table.h \
|
||||
indirect_texture_compression.c \
|
||||
glxbyteorder.h \
|
||||
glxcmds.c \
|
||||
glxcmdsswap.c \
|
||||
glxcontext.h \
|
||||
glxdrawable.h \
|
||||
glxext.c \
|
||||
glxext.h \
|
||||
glxdriswrast.c \
|
||||
glxdricommon.c \
|
||||
glxdricommon.h \
|
||||
glxscreens.c \
|
||||
glxscreens.h \
|
||||
glxserver.h \
|
||||
glxutil.h \
|
||||
render2.c \
|
||||
render2swap.c \
|
||||
renderpix.c \
|
||||
renderpixswap.c \
|
||||
rensize.c \
|
||||
single2.c \
|
||||
single2swap.c \
|
||||
singlepix.c \
|
||||
singlepixswap.c \
|
||||
singlesize.c \
|
||||
singlesize.h \
|
||||
swap_interval.c \
|
||||
unpack.h \
|
||||
xfont.c
|
||||
|
||||
libglx_la_LIBADD = $(DLOPEN_LIBS) $(top_builddir)/Xext/libhashtable.la
|
||||
|
||||
libglxvnd_la_SOURCES = \
|
||||
vndcmds.c \
|
||||
vndext.c \
|
||||
vndservermapping.c \
|
||||
vndservervendor.h \
|
||||
vndservervendor.c
|
||||
|
||||
libglxvnd_la_LIBADD = $(top_builddir)/Xext/libhashtable.la
|
||||
|
||||
EXTRA_DIST = vnd_dispatch_stubs.c
|
|
@ -993,7 +993,6 @@ __glXDisp_GetVisualConfigs(__GLXclientState * cl, GLbyte * pc)
|
|||
/* Pad with zeroes, so that attributes count is constant. */
|
||||
while (p < GLX_VIS_CONFIG_TOTAL) {
|
||||
buf[p++] = 0;
|
||||
buf[p++] = 0;
|
||||
}
|
||||
|
||||
assert(p == GLX_VIS_CONFIG_TOTAL);
|
||||
|
@ -1882,7 +1881,7 @@ DoGetDrawableAttributes(__GLXclientState * cl, XID drawId)
|
|||
int err = dixLookupWindow((WindowPtr *)&pDraw, drawId, client,
|
||||
DixGetAttrAccess);
|
||||
if (err != Success)
|
||||
return error;
|
||||
return __glXError(GLXBadDrawable);
|
||||
}
|
||||
if (pGlxDraw)
|
||||
pDraw = pGlxDraw->pDraw;
|
||||
|
|
|
@ -51,7 +51,7 @@ if build_glx
|
|||
endif
|
||||
|
||||
srcs_glxdri2 = []
|
||||
if build_dri3
|
||||
if build_dri2 or build_dri3
|
||||
srcs_glxdri2 = files('glxdri2.c')
|
||||
endif
|
||||
|
||||
|
@ -78,4 +78,8 @@ if build_glx
|
|||
dependency('gl', version: '>= 1.2'),
|
||||
],
|
||||
)
|
||||
|
||||
if build_xorg
|
||||
install_data(hdrs_vnd, install_dir : xorgsdkdir)
|
||||
endif
|
||||
endif
|
||||
|
|
|
@ -92,6 +92,9 @@ static void SetReplyHeader(ClientPtr client, void *replyPtr)
|
|||
xGenericReply *rep = (xGenericReply *) replyPtr;
|
||||
rep->type = X_Reply;
|
||||
rep->sequenceNumber = client->sequence;
|
||||
if (client->swapped) {
|
||||
swaps(&rep->sequenceNumber);
|
||||
}
|
||||
rep->length = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
if DMX
|
||||
DMX_SUBDIRS = dmx
|
||||
endif
|
||||
|
||||
if XORG
|
||||
XORG_SUBDIRS = xfree86
|
||||
endif
|
||||
|
||||
if XVFB
|
||||
XVFB_SUBDIRS = vfb
|
||||
endif
|
||||
|
||||
if XNEST
|
||||
XNEST_SUBDIRS = xnest
|
||||
endif
|
||||
|
||||
if XWIN
|
||||
XWIN_SUBDIRS = xwin
|
||||
endif
|
||||
|
||||
if KDRIVE
|
||||
KDRIVE_SUBDIRS = kdrive
|
||||
endif
|
||||
|
||||
if XQUARTZ
|
||||
XQUARTZ_SUBDIRS = xquartz
|
||||
endif
|
||||
|
||||
if XWAYLAND
|
||||
XWAYLAND_SUBDIRS = xwayland
|
||||
endif
|
||||
|
||||
SUBDIRS = \
|
||||
$(XORG_SUBDIRS) \
|
||||
$(XWIN_SUBDIRS) \
|
||||
$(XVFB_SUBDIRS) \
|
||||
$(XNEST_SUBDIRS) \
|
||||
$(DMX_SUBDIRS) \
|
||||
$(KDRIVE_SUBDIRS) \
|
||||
$(XQUARTZ_SUBDIRS) \
|
||||
$(XWAYLAND_SUBDIRS)
|
||||
|
||||
DIST_SUBDIRS = dmx xfree86 vfb xnest xwin xquartz kdrive xwayland
|
||||
|
||||
relink:
|
||||
$(AM_V_at)for i in $(SUBDIRS) ; do $(MAKE) -C $$i relink || exit 1 ; done
|
|
@ -0,0 +1,2 @@
|
|||
# Add & Override for this directory and its subdirectories
|
||||
Xdmx
|
|
@ -0,0 +1,87 @@
|
|||
|
||||
SUBDIRS = input config examples doc doxygen man
|
||||
bin_PROGRAMS = Xdmx
|
||||
|
||||
if XINERAMA
|
||||
PANORAMIX_SRCS = $(top_srcdir)/Xext/panoramiX.c
|
||||
endif
|
||||
|
||||
if GLX
|
||||
SUBDIRS += glxProxy
|
||||
GLX_LIBS = glxProxy/libglxproxy.a
|
||||
GLX_SRCS = $(PANORAMIX_SRCS) dmx_glxvisuals.c dmx_glxvisuals.h
|
||||
GLX_INCS = -I$(top_srcdir)/hw/xfree86/dixmods/extmod
|
||||
GLX_DEFS = @GL_CFLAGS@
|
||||
endif
|
||||
|
||||
AM_CFLAGS = \
|
||||
-DHAVE_DMX_CONFIG_H \
|
||||
$(DIX_CFLAGS) \
|
||||
$(GLX_INCS) \
|
||||
$(GLX_DEFS) \
|
||||
$(DMX_CFLAGS) \
|
||||
@DMXMODULES_CFLAGS@
|
||||
|
||||
Xdmx_SOURCES = dmx.c \
|
||||
dmxcb.c \
|
||||
dmxcb.h \
|
||||
dmxclient.h \
|
||||
dmxcmap.c \
|
||||
dmxcmap.h \
|
||||
dmx-config.h \
|
||||
dmxcursor.c \
|
||||
dmxcursor.h \
|
||||
dmxdpms.c \
|
||||
dmxdpms.h \
|
||||
dmxextension.c \
|
||||
dmxextension.h \
|
||||
dmxfont.c \
|
||||
dmxfont.h \
|
||||
dmxgc.c \
|
||||
dmxgc.h \
|
||||
dmxgcops.c \
|
||||
dmxgcops.h \
|
||||
dmx.h \
|
||||
dmxinit.c \
|
||||
dmxinit.h \
|
||||
dmxinput.c \
|
||||
dmxinput.h \
|
||||
dmxlog.c \
|
||||
dmxlog.h \
|
||||
dmxpict.c \
|
||||
dmxpict.h \
|
||||
dmxpixmap.c \
|
||||
dmxpixmap.h \
|
||||
dmxprop.c \
|
||||
dmxprop.h \
|
||||
dmxscrinit.c \
|
||||
dmxscrinit.h \
|
||||
dmxstat.c \
|
||||
dmxstat.h \
|
||||
dmxsync.c \
|
||||
dmxsync.h \
|
||||
dmxvisual.c \
|
||||
dmxvisual.h \
|
||||
dmxwindow.c \
|
||||
dmxwindow.h \
|
||||
$(top_srcdir)/mi/miinitext.c \
|
||||
$(top_srcdir)/mi/miinitext.h \
|
||||
$(GLX_SRCS)
|
||||
|
||||
|
||||
#if COMPOSITE
|
||||
#Xdmx_SOURCES += fakecw.c
|
||||
#endif
|
||||
|
||||
XDMX_LIBS = \
|
||||
$(GLX_LIBS) \
|
||||
@XDMX_LIBS@ \
|
||||
input/libdmxinput.a \
|
||||
config/libdmxconfig.a
|
||||
|
||||
Xdmx_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG)
|
||||
Xdmx_DEPENDENCIES= $(XDMX_LIBS)
|
||||
Xdmx_LDADD = $(XDMX_LIBS) $(XDMX_SYS_LIBS) $(XSERVER_SYS_LIBS)
|
||||
|
||||
relink:
|
||||
$(AM_V_at)rm -f Xdmx$(EXEEXT) && $(MAKE) Xdmx$(EXEEXT)
|
|
@ -0,0 +1,7 @@
|
|||
# Add & Override for this directory and its subdirectories
|
||||
dmxtodmx
|
||||
parser.c
|
||||
parser.h
|
||||
scanner.c
|
||||
vdltodmx
|
||||
xdmxconfig
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright 1987, 1998 The Open Group
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The above copyright notice and this permission notice 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
|
||||
* OPEN GROUP 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.
|
||||
*
|
||||
* Except as contained in this notice, the name of The Open Group shall not be
|
||||
* used in advertising or otherwise to promote the sale, use or other dealings
|
||||
* in this Software without prior written authorization from The Open Group.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2002 Red Hat Inc., Durham, North Carolina.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* 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 on 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
|
||||
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
|
||||
* 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:
|
||||
* Rickard E. (Rik) Faith <faith@redhat.com>
|
||||
*
|
||||
* This file was originally taken from xc/lib/Xaw/Template.c
|
||||
*/
|
||||
|
||||
#include <X11/IntrinsicP.h>
|
||||
#include <X11/StringDefs.h>
|
||||
#include "CanvasP.h"
|
||||
|
||||
static void
|
||||
CanvasInitialize(Widget request, Widget w, ArgList args, Cardinal * num_args)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
CanvasExpose(Widget w, XEvent * event, Region region)
|
||||
{
|
||||
CanvasExposeDataRec data;
|
||||
|
||||
data.w = w;
|
||||
data.event = event;
|
||||
data.region = region;
|
||||
|
||||
if (!XtIsRealized(w))
|
||||
return;
|
||||
XtCallCallbacks(w, XtNcanvasExposeCallback, (XtPointer) &data);
|
||||
}
|
||||
|
||||
static void
|
||||
CanvasResize(Widget w)
|
||||
{
|
||||
if (!XtIsRealized(w))
|
||||
return;
|
||||
XtCallCallbacks(w, XtNcanvasResizeCallback, (XtPointer) w);
|
||||
}
|
||||
|
||||
static void
|
||||
CanvasAction(Widget w, XEvent * event, String * params, Cardinal * num_params)
|
||||
{
|
||||
XtCallCallbacks(w, XtNcallback, (XtPointer) event);
|
||||
}
|
||||
|
||||
#define offset(field) XtOffsetOf(CanvasRec, canvas.field)
|
||||
static XtResource resources[] = {
|
||||
{XtNcallback, XtCCallback, XtRCallback,
|
||||
sizeof(XtCallbackList), offset(input_callback), XtRCallback, NULL}
|
||||
,
|
||||
{(char *) XtNcanvasExposeCallback, (char *) XtCcanvasExposeCallback, XtRCallback,
|
||||
sizeof(XtCallbackList), offset(expose_callback), XtRCallback, NULL}
|
||||
,
|
||||
{(char *) XtNcanvasResizeCallback, (char *) XtCcanvasResizeCallback, XtRCallback,
|
||||
sizeof(XtCallbackList), offset(resize_callback), XtRCallback, NULL}
|
||||
,
|
||||
};
|
||||
|
||||
#undef offset
|
||||
|
||||
static XtActionsRec actions[] = {
|
||||
{(char *) "canvas", CanvasAction},
|
||||
};
|
||||
|
||||
static char translations[] = "<Key>: canvas()\n\
|
||||
<Motion>: canvas()\n\
|
||||
<BtnDown>: canvas()\n\
|
||||
<BtnUp>: canvas()\n\
|
||||
";
|
||||
|
||||
#define Superclass (&widgetClassRec)
|
||||
CanvasClassRec canvasClassRec = {
|
||||
/* core */
|
||||
{
|
||||
(WidgetClass) Superclass, /* superclass */
|
||||
(char *) "Canvas", /* class_name */
|
||||
sizeof(CanvasRec), /* widget_size */
|
||||
NULL, /* class_initialize */
|
||||
NULL, /* class_part_initialize */
|
||||
False, /* class_inited */
|
||||
CanvasInitialize, /* initialize */
|
||||
NULL, /* initialize_hook */
|
||||
XtInheritRealize, /* realize */
|
||||
actions, /* actions */
|
||||
XtNumber(actions), /* num_actions */
|
||||
resources, /* resources */
|
||||
XtNumber(resources), /* num_resources */
|
||||
NULLQUARK, /* xrm_class */
|
||||
True, /* compress_motion */
|
||||
True, /* compress_exposure */
|
||||
True, /* compress_enterleave */
|
||||
False, /* visible_interest */
|
||||
NULL, /* destroy */
|
||||
CanvasResize, /* resize */
|
||||
CanvasExpose, /* expose */
|
||||
NULL, /* set_values */
|
||||
NULL, /* set_values_hook */
|
||||
XtInheritSetValuesAlmost, /* set_values_almost */
|
||||
NULL, /* get_values_hook */
|
||||
NULL, /* accept_focus */
|
||||
XtVersion, /* version */
|
||||
NULL, /* callback_private */
|
||||
translations, /* tm_table */
|
||||
XtInheritQueryGeometry, /* query_geometry */
|
||||
XtInheritDisplayAccelerator, /* display_accelerator */
|
||||
NULL, /* extension */
|
||||
}
|
||||
,
|
||||
/* canvas */
|
||||
{
|
||||
NULL, /* extension */
|
||||
}
|
||||
};
|
||||
|
||||
WidgetClass canvasWidgetClass = (WidgetClass) &canvasClassRec;
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
|
||||
Copyright 1987, 1998 The Open Group
|
||||
Copyright 2002 Red Hat Inc., Durham, North Carolina.
|
||||
|
||||
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.
|
||||
|
||||
The above copyright notice and this permission notice 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
|
||||
OPEN GROUP 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.
|
||||
|
||||
Except as contained in this notice, the name of The Open Group shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from The Open Group.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Authors:
|
||||
* Rickard E. (Rik) Faith <faith@redhat.com>
|
||||
*
|
||||
* This file was originally taken from xc/lib/Xaw/Template.h
|
||||
*/
|
||||
|
||||
#ifndef _Canvas_h
|
||||
#define _Canvas_h
|
||||
|
||||
#include <X11/Intrinsic.h>
|
||||
|
||||
#define XtNcanvasExposeCallback "canvasExposeCallback"
|
||||
#define XtCcanvasExposeCallback "CanvasExposeCallback"
|
||||
#define XtNcanvasResizeCallback "canvasResizeCallback"
|
||||
#define XtCcanvasResizeCallback "CanvasResizeCallback"
|
||||
|
||||
typedef struct _CanvasClassRec *CanvasWidgetClass;
|
||||
typedef struct _CanvasRec *CanvasWidget;
|
||||
extern WidgetClass canvasWidgetClass;
|
||||
|
||||
typedef struct _CanvasExposeDataRec {
|
||||
Widget w;
|
||||
XEvent *event;
|
||||
Region region;
|
||||
} CanvasExposeDataRec, *CanvasExposeDataPtr;
|
||||
|
||||
#endif /* _Canvas_h */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue