Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • chengbo7135/xserver
  • wjp/xserver
  • DemiMarie/xserver
  • guillem/xserver
  • uvas/xserver
  • cl91/xserver
  • heymiaoO/xserver
  • oreaus/xserver
  • stapelberg/xserver
  • PaulKocialkowski/xserver
  • CendioOssman/xserver
  • wiz/xserver
  • maos20008/xserver
  • dougvj/xserver
  • mgorse1/xserver
  • gldrk/xserver
  • TMR5454/xserver
  • rc_05/xserver
  • Kyawswat/xserver
  • hexiaodong/xserver
  • gilvbp/xserver
  • vliaskov/xserver
  • zzyiwei/xserver
  • aarondill/xserver
  • kleinerm/xserver
  • jcherry/xserver
  • jcristau/xserver
  • nathankidd/xserver
  • jexposit/xserver
  • refi_64/xserver
  • kbrenneman/xserver
  • kupper.pa/xserver
  • LickmeDown/xserver
  • zboszor/xserver
  • jadahl/xserver
  • shadeslayer/xserver
  • mherrb/xserver
  • Julia/xserver
  • twaik/xserver
  • fvalasiad/xserver
  • zzxyb/xserver
  • HermannSW/xserver
  • erwinou/xserver
  • ekurzinger/xserver
  • nacho.resa/xserver
  • agoins/xserver
  • NSUTanghaixiang/xserver
  • p12tic/xserver
  • huxd1532/xserver
  • keithp/xserver
  • vinilokorlok/xserver
  • bbeckett/xserver
  • dslater38/xserver
  • zzag/xserver
  • emersion/xserver
  • djlucas/xserver
  • ccullumbine2018/xserver
  • daniels/xserver
  • llandwerlin/xserver
  • matt335672/xserver
  • doraskayo/xserver
  • afett/xserver
  • XDXTHX/xserver
  • xexaxo/xserver
  • ecurtin/xserver
  • rbernon/xserver
  • pekdon/xserver
  • karolherbst/xserver
  • russellcnv/xserver
  • mbiebl/xserver
  • orbea/xserver
  • vsyrjala/xserver
  • lyudess/xserver
  • manu/xserver
  • lucmann/xserver
  • tholin/xserver
  • yarivb/xserver
  • tmlind/xserver
  • chema/xserver
  • J-Bu/xserver
  • chenhuacai/xserver
  • E5ten/xserver
  • haagch/xserver
  • whot/xserver
  • strassek/xserver
  • mntmn/xserver
  • liyi42/xserver
  • YusufKhan-gamedev/xserver
  • iv-m/xserver
  • vanvugt/xserver
  • alanc/xserver
  • Rui511/xserver
  • catap/xserver
  • tjbp/xserver
  • webi123/xserver
  • noblock/xserver
  • freemangordon/xserver
  • xdandys/xserver
  • jbeich/xserver
  • zeising/xserver
  • romangg/xserver
  • pq/xserver
  • azhadchenko/xserver
  • Emantor/xserver
  • carlosg/xserver
  • kwg/xserver
  • pichika/xserver
  • klniu/xserver
  • TAAPArthur/xserver
  • sjoerd/xserver
  • Sjecai2/xserver
  • jturney/xserver
  • pkubaj/xserver
  • os369510/xserver
  • xorg/xserver
  • Zamundaaa/xserver
  • Gorg/xserver
  • ForTheReallys/xserver
  • lkundrak/xserver
  • niveditharau/xserver
  • jmonteiro/xserver
  • jocelyn/xserver
  • ThatMG393/xserver
  • fweimer/xserver
  • mlankhorst/xserver
  • marv/xserver
  • dbn/xserver
  • mattrope/xserver
  • coypoop/xserver
  • mwyraz/xserver
  • frog/xserver
  • 3v1n0/xserver
  • awilfox/xserver
  • muesli4/xserver
  • rarbab/xserver
  • yshui/xserver
  • jannau/xserver
  • mikeroyal/xserver
  • andrebsguedes/xserver
  • ipominov/xserver
  • JeffyCN/xserver
  • gtrentalancia/xserver
  • josch/xserver
  • lucyllewy/xserver
  • tomty89/xserver
  • qarmin/xserver
  • tagr/xserver
  • zwenna/xserver
  • bkylerussell/xserver
  • mupuf/xserver
  • zubzub/xserver
  • galaxytgtabiday/xserver
  • OlCe/xserver
  • ashafer/xserver
  • dengbo/xserver
  • valpackett/xserver
  • andreyknyazev077/xserver
  • antonovitch/xserver
  • contactshashanksharma/xserver-fork-shashank
  • akihiko.odaki/xserver
  • sknsean/xserver
  • rnpnr/xserver
  • hitong602/xserver
  • halfline/xserver
  • ismailsiege/xserver
  • dongwonk/xserver
  • Fatton1/xserver
  • GermanAizek/xserver
  • daenzer/xserver
  • FeepingCreature/xserver
  • mvlad/xserver
  • puleglot/xserver
  • smelenius/xserver
  • sewn/xserver
  • kaichuan.hsieh/xserver
  • SimonPilkington/xserver
  • adamdruppe/xserver
  • floppym/xserver
  • luke-jr/xserver
  • trevdave/xserver
  • headrush/xserver
  • davidriley/xserver
  • heitbaum/xserver
  • mrisaacb/xserver
  • goosen78/xserver
  • Ma/xserver
  • gmbr3/xserver
  • tsutsui/xserver
  • sherrodejjohnson/xserver
  • hassoon1986/xserver
  • lanodan/xserver
  • ydc-dadada/xserver
  • wengxt/xserver
  • icenowy/xserver
  • denisfa/xserver
  • StarsGreen/xserver
  • adamjrichter/xserver
  • bigon/xserver
  • djacewicz/xserver
  • davidre/xserver
  • kylin0061/xserver
  • arrowd/xserver
  • ernstp/xserver
  • bbrezillon/xserver
  • penguin42/xserver
  • anarsoul/xserver
  • marvinjr35/xserver
  • gerddie/xserver
  • xry111/xserver
  • psyruss85/xserver
  • volkanorhan/xserver
  • nicolas-guichard/xserver
  • yangxiaojuan-loongson/xserver
  • luporl/xserver
  • cbur201592/xserver
  • bphaslett/xserver
  • haihao/xserver
  • peterh/xserver
  • miztake/xserver
  • zaps166/xserver
  • lostgoat/xserver
  • vfjpl/xserver
  • bentiss/xserver
  • rilian-la-te/xserver
  • wujiangGitHub/xserver
  • cubanismo/xserver
  • arichardson/xserver
  • schreibemirhalt/xserver
  • jsg/xserver
  • karlosrangel337/xserver
  • knisht/xserver
  • manuelcrack642/xserver
  • ross/xserver
  • topimiettinen/xserver
  • davidedmundson/xserver
  • DPA/xserver
  • dkorkmazturk/xserver
  • karamjameelmoore/xserver
  • lihongtao/xserver
  • sthibaul/xserver
  • RyzenDew/xserver
  • christian-rauch/xserver
  • Vivek/xserver
  • peigongdsd/xserver
  • peng.jin/xserver
  • alagner/xserver
  • mehdigh419/xserver
  • dixler/xserver
  • BBaoVanC/xserver
  • Drakulix/xserver
  • Acidburn0zzz/xserver
  • bafanahub/xserver
  • benpicco/xserver
  • kaocher82/xserver
  • pepp/xserver
  • cgzones/xserver
  • luyn/xserver
  • 1740301466jxz/xserver
  • ids1024/xserver
  • svalaskevicius/xserver
  • ZhiJie.Zhang/xserver
  • eschwartz/xserver
  • jayantpranjal0/xserver
  • hmazlan/xserver
  • kerneltoast/xserver
  • Michaelypk/xserver
  • dottedmag/xserver
  • aplattner/xserver
  • sergiomb/xserver
  • metux/xserver
  • looi/xserver
  • robclark/xserver
  • tzimmermann/xserver
  • vitoux.pascal/xserver
  • aditj/xserver
  • kennylevinsen/xserver
  • Kishore409/xserver
  • Daasin/xserver
  • dirbaio/xserver
  • xinbowang/xserver
  • mwei/xserver
  • SpikyCaterpillar1/xserver
  • devin11911191/xserver
  • alex-tu-cc/xserver
  • kaniini/xserver
  • jcourreges/xserver
  • n3rdopolis/xserver
  • zagursky/xserver
  • thesamesam/xserver
  • anholt/xserver
  • themaister/xserver
  • jrtc27/xserver
  • JoseExposito/xserver
  • Hi-Angel/xserver
  • City-busz/xserver
  • ydirson/xserver
  • dawnhan/xserver
  • avolkov/xserver
  • meMuszr/xserver
  • dk/xserver
  • cooperch/xserver
  • Tuetuopay/xserver
  • gabifalk/xserver
  • jeremyhu/xserver
  • 1480c1/xserver
  • Spintzyk/xserver
  • MisterDA/xserver
  • starnight/xserver
  • abono/xserver
  • ajax/xserver
  • dougg3/xserver
  • chenx_dust/xserver
  • EXtremeExploit/xserver
  • jwrdegoede/xserver
  • road2react/xserver
  • acelan/xserver
  • airlied/xserver
  • gfxstrand/xorg-xserver
  • justazarsky/xserver
  • sri-ka1ki/xserver
  • rgfernandes/xserver
  • lynxeye/xserver
  • tintou/xserver
  • mattst88/xserver
  • rmader/xserver
  • linkmauve/xserver
  • kamarul6401/xserver
  • andy-zetier/xserver
  • gsittyz/xserver
  • bernhardu/xserver
  • causztic/xserver
  • cpmichael/modesetting
  • ryanneph/xserver
  • zhangyaning/xserver
  • olv/xserver
  • hongaoo/xserver
  • LiChenG-P/xserver
  • Ivaniku/x-taylan
  • dkg/xserver
  • ofourdan/xserver
  • mahkoh/xserver
  • AkiSakurai/xserver
  • msizanoen1/xserver
343 results
Show changes
Commits on Source (15)
Showing
with 720 additions and 132 deletions
......@@ -19,7 +19,7 @@ variables:
FDO_UPSTREAM_REPO: xorg/xserver
FDO_DISTRIBUTION_VERSION: bullseye-slim
FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} bash .gitlab-ci/debian-install.sh'
FDO_DISTRIBUTION_TAG: "2022-09-02-fixed-commits"
FDO_DISTRIBUTION_TAG: "2022-11-24-new-wayland-protocols"
include:
- project: 'freedesktop/ci-templates'
......
......@@ -129,11 +129,19 @@ make -j${FDO_CI_CONCURRENT:-4} install
popd
rm -rf xorgproto
# Xwayland requires wayland-protocols >= 1.22, but Debian bullseye has 1.20 only
git clone https://gitlab.freedesktop.org/wayland/wayland-protocols.git --depth 1 --branch=1.22
# wayland-protocols requires wayland-scanner 1.20, but Debian bullseye has 1.18 only
git clone https://gitlab.freedesktop.org/wayland/wayland.git --depth 1 --branch=1.21.0
cd wayland
meson -Dtests=false -Ddocumentation=false -Ddtd_validation=false _build
ninja -C _build -j${FDO_CI_CONCURRENT:-4} install
cd ..
rm -rf wayland
# Xwayland requires wayland-protocols >= 1.28, but Debian bullseye has 1.20 only
git clone https://gitlab.freedesktop.org/wayland/wayland-protocols.git --depth 1 --branch=1.28
cd wayland-protocols
./autogen.sh
make -j${FDO_CI_CONCURRENT:-4} install
meson _build
ninja -C _build -j${FDO_CI_CONCURRENT:-4} install
cd ..
rm -rf wayland-protocols
......
......@@ -262,12 +262,11 @@ PixmapStopDirtyTracking(DrawablePtr src, PixmapPtr secondary_dst)
return TRUE;
}
static void
PixmapDirtyCopyArea(PixmapPtr dst,
PixmapDirtyUpdatePtr dirty,
void
PixmapDirtyCopyArea(PixmapPtr dst, DrawablePtr src,
int x, int y, int dst_x, int dst_y,
RegionPtr dirty_region)
{
DrawablePtr src = dirty->src;
ScreenPtr pScreen = src->pScreen;
int n;
BoxPtr b;
......@@ -294,9 +293,8 @@ PixmapDirtyCopyArea(PixmapPtr dst,
h = dst_box.y2 - dst_box.y1;
pGC->ops->CopyArea(src, &dst->drawable, pGC,
dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h,
dirty->dst_x + dst_box.x1,
dirty->dst_y + dst_box.y1);
x + dst_box.x1, y + dst_box.y1, w, h,
dst_x + dst_box.x1, dst_y + dst_box.y1);
b++;
}
FreeScratchGC(pGC);
......@@ -408,7 +406,8 @@ Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty)
RegionTranslate(&pixregion, -dirty->x, -dirty->y);
if (!pScreen->root || dirty->rotation == RR_Rotate_0)
PixmapDirtyCopyArea(dst, dirty, &pixregion);
PixmapDirtyCopyArea(dst, dirty->src, dirty->x, dirty->y,
dirty->dst_x, dirty->dst_y, &pixregion);
else
PixmapDirtyCompositeRotate(dst, dirty, &pixregion);
pScreen->SourceValidate = SourceValidate;
......
......@@ -74,7 +74,7 @@
* mask is 0xFFFF0000.
*/
#define ABI_ANSIC_VERSION SET_ABI_VERSION(0, 4)
#define ABI_VIDEODRV_VERSION SET_ABI_VERSION(25, 3)
#define ABI_VIDEODRV_VERSION SET_ABI_VERSION(25, 4)
#define ABI_XINPUT_VERSION SET_ABI_VERSION(24, 4)
#define ABI_EXTENSION_VERSION SET_ABI_VERSION(10, 0)
......
......@@ -145,6 +145,7 @@ static const OptionInfoRec Options[] = {
{OPTION_VARIABLE_REFRESH, "VariableRefresh", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_USE_GAMMA_LUT, "UseGammaLUT", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_ASYNC_FLIP_SECONDARIES, "AsyncFlipSecondaries", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_TEARFREE, "TearFree", OPTV_BOOLEAN, {0}, FALSE},
{-1, NULL, OPTV_NONE, {0}, FALSE}
};
......@@ -548,14 +549,16 @@ rotate_clip(PixmapPtr pixmap, BoxPtr rect, drmModeClip *clip, Rotation rotation)
}
static int
dispatch_dirty_region(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
PixmapPtr pixmap, DamagePtr damage, int fb_id)
dispatch_damages(ScrnInfoPtr scrn, xf86CrtcPtr crtc, RegionPtr dirty,
PixmapPtr pixmap, DamagePtr damage, int fb_id)
{
modesettingPtr ms = modesettingPTR(scrn);
RegionPtr dirty = DamageRegion(damage);
unsigned num_cliprects = REGION_NUM_RECTS(dirty);
int ret = 0;
if (!ms->dirty_enabled)
return 0;
if (num_cliprects) {
drmModeClip *clip = xallocarray(num_cliprects, sizeof(drmModeClip));
BoxPtr rect = REGION_RECTS(dirty);
......@@ -579,12 +582,102 @@ dispatch_dirty_region(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
}
}
if (ret == -EINVAL || ret == -ENOSYS) {
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"Disabling kernel dirty updates, not required.\n");
ms->dirty_enabled = FALSE;
}
free(clip);
DamageEmpty(damage);
if (damage)
DamageEmpty(damage);
}
return ret;
}
static int
dispatch_dirty_region(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
PixmapPtr pixmap, DamagePtr damage, int fb_id)
{
return dispatch_damages(scrn, crtc, DamageRegion(damage),
pixmap, damage, fb_id);
}
static void
ms_tearfree_update_damages(ScreenPtr pScreen)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
modesettingPtr ms = modesettingPTR(scrn);
RegionPtr dirty = DamageRegion(ms->damage);
int c, i;
if (RegionNil(dirty))
return;
for (c = 0; c < xf86_config->num_crtc; c++) {
xf86CrtcPtr crtc = xf86_config->crtc[c];
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
RegionRec region;
/* Compute how much of the damage intersects with this CRTC */
RegionInit(&region, &crtc->bounds, 0);
RegionIntersect(&region, &region, dirty);
if (trf->buf[0].px) {
for (i = 0; i < ARRAY_SIZE(trf->buf); i++)
RegionUnion(&trf->buf[i].dmg, &trf->buf[i].dmg, &region);
} else {
/* Just notify the kernel of the damages if TearFree isn't used */
dispatch_damages(scrn, crtc, &region,
pScreen->GetScreenPixmap(pScreen),
NULL, ms->drmmode.fb_id);
}
}
DamageEmpty(ms->damage);
}
static void
ms_tearfree_do_flips(ScreenPtr pScreen)
{
#ifdef GLAMOR_HAS_GBM
ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
modesettingPtr ms = modesettingPTR(scrn);
int c;
if (!ms->drmmode.tearfree_enable)
return;
for (c = 0; c < xf86_config->num_crtc; c++) {
xf86CrtcPtr crtc = xf86_config->crtc[c];
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
/* Skip disabled CRTCs and those which aren't using TearFree */
if (!trf->buf[0].px || !crtc->scrn->vtSema || !xf86_crtc_on(crtc))
continue;
/* Skip if the last flip is still pending, a DRI client is flipping, or
* there isn't any damage on the front buffer.
*/
if (trf->flip_seq || ms->drmmode.dri2_flipping ||
ms->drmmode.present_flipping ||
RegionNil(&trf->buf[trf->back_idx ^ 1].dmg))
continue;
/* Flip. If it fails, notify the kernel of the front buffer damages */
if (ms_do_tearfree_flip(pScreen, crtc)) {
dispatch_damages(scrn, crtc, &trf->buf[trf->back_idx ^ 1].dmg,
trf->buf[trf->back_idx ^ 1].px, NULL,
trf->buf[trf->back_idx ^ 1].fb_id);
RegionEmpty(&trf->buf[trf->back_idx ^ 1].dmg);
}
}
#endif
}
static void
dispatch_dirty(ScreenPtr pScreen)
{
......@@ -606,12 +699,9 @@ dispatch_dirty(ScreenPtr pScreen)
ret = dispatch_dirty_region(scrn, crtc, pixmap, ms->damage, fb_id);
if (ret == -EINVAL || ret == -ENOSYS) {
ms->dirty_enabled = FALSE;
DamageUnregister(ms->damage);
DamageDestroy(ms->damage);
ms->damage = NULL;
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"Disabling kernel dirty updates, not required.\n");
return;
}
}
......@@ -742,10 +832,13 @@ msBlockHandler(ScreenPtr pScreen, void *timeout)
pScreen->BlockHandler = msBlockHandler;
if (pScreen->isGPU && !ms->drmmode.reverse_prime_offload_mode)
dispatch_secondary_dirty(pScreen);
else if (ms->drmmode.tearfree_enable)
ms_tearfree_update_damages(pScreen);
else if (ms->dirty_enabled)
dispatch_dirty(pScreen);
ms_dirty_update(pScreen, timeout);
ms_tearfree_do_flips(pScreen);
}
static void
......@@ -1277,9 +1370,34 @@ PreInit(ScrnInfoPtr pScrn, int flags)
if (xf86ReturnOptValBool(ms->drmmode.Options, OPTION_ATOMIC, FALSE)) {
ret = drmSetClientCap(ms->fd, DRM_CLIENT_CAP_ATOMIC, 1);
ms->atomic_modeset = (ret == 0);
if (!ms->atomic_modeset)
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Atomic modesetting not supported\n");
} else {
ms->atomic_modeset = FALSE;
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Atomic modesetting %sabled\n", ms->atomic_modeset ? "en" : "dis");
/* TearFree requires glamor and, if PageFlip is enabled, universal planes */
if (xf86ReturnOptValBool(ms->drmmode.Options, OPTION_TEARFREE, FALSE)) {
if (pScrn->is_gpu) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"TearFree cannot synchronize PRIME; use 'PRIME Synchronization' instead\n");
} else if (ms->drmmode.glamor) {
/* Atomic modesetting implicitly enables universal planes */
if (!ms->drmmode.pageflip || ms->atomic_modeset ||
!drmSetClientCap(ms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) {
ms->drmmode.tearfree_enable = TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TearFree: enabled\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"TearFree requires either universal planes, or setting 'Option \"PageFlip\" \"off\"'\n");
}
} else {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"TearFree requires Glamor acceleration\n");
}
}
ms->kms_has_modifiers = FALSE;
ret = drmGetCap(ms->fd, DRM_CAP_ADDFB2_MODIFIERS, &value);
......@@ -1628,13 +1746,13 @@ CreateScreenResources(ScreenPtr pScreen)
err = drmModeDirtyFB(ms->fd, ms->drmmode.fb_id, NULL, 0);
if (err != -EINVAL && err != -ENOSYS) {
if ((err != -EINVAL && err != -ENOSYS) || ms->drmmode.tearfree_enable) {
ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE,
pScreen, rootPixmap);
if (ms->damage) {
DamageRegister(&rootPixmap->drawable, ms->damage);
ms->dirty_enabled = TRUE;
ms->dirty_enabled = err != -EINVAL && err != -ENOSYS;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n");
}
else {
......
......@@ -61,6 +61,7 @@ typedef enum {
OPTION_VARIABLE_REFRESH,
OPTION_USE_GAMMA_LUT,
OPTION_ASYNC_FLIP_SECONDARIES,
OPTION_TEARFREE,
} modesettingOpts;
typedef struct
......@@ -86,10 +87,13 @@ struct ms_drm_queue {
struct xorg_list list;
xf86CrtcPtr crtc;
uint32_t seq;
uint64_t msc;
void *data;
ScrnInfoPtr scrn;
ms_drm_handler_proc handler;
ms_drm_abort_proc abort;
Bool kernel_queued;
Bool aborted;
};
typedef struct _modesettingRec {
......@@ -238,6 +242,8 @@ Bool ms_do_pageflip(ScreenPtr screen,
ms_pageflip_abort_proc pageflip_abort,
const char *log_prefix);
Bool ms_do_tearfree_flip(ScreenPtr screen, xf86CrtcPtr crtc);
#endif
int ms_flush_drm_events(ScreenPtr screen);
......
......@@ -632,6 +632,7 @@ drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
int ret;
*fb_id = 0;
......@@ -646,6 +647,10 @@ drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y)
*x = drmmode_crtc->prime_pixmap_x;
*y = 0;
}
else if (trf->buf[trf->back_idx ^ 1].px) {
*fb_id = trf->buf[trf->back_idx ^ 1].fb_id;
*x = *y = 0;
}
else if (drmmode_crtc->rotate_fb_id) {
*fb_id = drmmode_crtc->rotate_fb_id;
*x = *y = 0;
......@@ -922,6 +927,10 @@ drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only)
drmmode_ConvertToKMode(crtc->scrn, &kmode, &crtc->mode);
ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
fb_id, x, y, output_ids, output_count, &kmode);
if (!ret && !ms->atomic_modeset) {
drmmode_crtc->src_x = x;
drmmode_crtc->src_y = y;
}
drmmode_set_ctm(crtc, ctm);
......@@ -930,7 +939,8 @@ drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only)
}
int
drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data)
drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, int x, int y,
uint32_t flags, void *data)
{
modesettingPtr ms = modesettingPTR(crtc->scrn);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
......@@ -942,7 +952,7 @@ drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data)
if (!req)
return 1;
ret = plane_add_props(req, crtc, fb_id, crtc->x, crtc->y);
ret = plane_add_props(req, crtc, fb_id, x, y);
flags |= DRM_MODE_ATOMIC_NONBLOCK;
if (ret == 0)
ret = drmModeAtomicCommit(ms->fd, req, flags, data);
......@@ -950,6 +960,26 @@ drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data)
return ret;
}
/* The frame buffer source coordinates may change when switching between the
* primary frame buffer and a per-CRTC frame buffer. Set the correct source
* coordinates if they differ for this flip.
*/
if (drmmode_crtc->src_x != x || drmmode_crtc->src_y != y) {
ret = drmModeSetPlane(ms->fd, drmmode_crtc->plane_id,
drmmode_crtc->mode_crtc->crtc_id, fb_id, 0,
0, 0, crtc->mode.HDisplay, crtc->mode.VDisplay,
x << 16, y << 16, crtc->mode.HDisplay << 16,
crtc->mode.VDisplay << 16);
if (ret) {
xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING,
"error changing fb src coordinates for flip: %d\n", ret);
return ret;
}
drmmode_crtc->src_x = x;
drmmode_crtc->src_y = y;
}
return drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
fb_id, flags, data);
}
......@@ -1548,6 +1578,90 @@ drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
#endif
}
void
drmmode_copy_damage(xf86CrtcPtr crtc, PixmapPtr dst, RegionPtr dmg, Bool empty)
{
#ifdef GLAMOR_HAS_GBM
ScreenPtr pScreen = xf86ScrnToScreen(crtc->scrn);
DrawableRec *src;
/* Copy the screen's pixmap into the destination pixmap */
if (crtc->rotatedPixmap) {
src = &crtc->rotatedPixmap->drawable;
xf86RotateCrtcRedisplay(crtc, dst, src, dmg, FALSE);
} else {
src = &pScreen->GetScreenPixmap(pScreen)->drawable;
PixmapDirtyCopyArea(dst, src, 0, 0, -crtc->x, -crtc->y, dmg);
}
/* Reset the damages if requested */
if (empty)
RegionEmpty(dmg);
/* Wait until the GC operations finish */
modesettingPTR(crtc->scrn)->glamor.finish(pScreen);
#endif
}
static void
drmmode_shadow_fb_destroy(xf86CrtcPtr crtc, PixmapPtr pixmap,
void *data, drmmode_bo *bo, uint32_t *fb_id);
static void
drmmode_destroy_tearfree_shadow(xf86CrtcPtr crtc)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
int i;
if (trf->flip_seq)
ms_drm_abort_seq(crtc->scrn, trf->flip_seq);
for (i = 0; i < ARRAY_SIZE(trf->buf); i++) {
if (trf->buf[i].px) {
drmmode_shadow_fb_destroy(crtc, trf->buf[i].px, (void *)(long)1,
&trf->buf[i].bo, &trf->buf[i].fb_id);
trf->buf[i].px = NULL;
RegionUninit(&trf->buf[i].dmg);
}
}
}
static PixmapPtr
drmmode_shadow_fb_create(xf86CrtcPtr crtc, void *data, int width, int height,
drmmode_bo *bo, uint32_t *fb_id);
static Bool
drmmode_create_tearfree_shadow(xf86CrtcPtr crtc)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
uint32_t w = crtc->mode.HDisplay, h = crtc->mode.VDisplay;
int i;
if (!drmmode->tearfree_enable)
return TRUE;
/* Destroy the old mode's buffers and make new ones */
drmmode_destroy_tearfree_shadow(crtc);
for (i = 0; i < ARRAY_SIZE(trf->buf); i++) {
trf->buf[i].px = drmmode_shadow_fb_create(crtc, NULL, w, h,
&trf->buf[i].bo,
&trf->buf[i].fb_id);
if (!trf->buf[i].px) {
drmmode_destroy_tearfree_shadow(crtc);
xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
"shadow creation failed for TearFree buf%d\n", i);
return FALSE;
}
RegionInit(&trf->buf[i].dmg, &crtc->bounds, 0);
}
/* Initialize the front buffer with the current scanout */
drmmode_copy_damage(crtc, trf->buf[trf->back_idx ^ 1].px,
&trf->buf[trf->back_idx ^ 1].dmg, TRUE);
return TRUE;
}
static Bool
drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rotation rotation, int x, int y)
......@@ -1581,6 +1695,10 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
crtc->gamma_blue, crtc->gamma_size);
ret = drmmode_create_tearfree_shadow(crtc);
if (!ret)
goto done;
can_test = drmmode_crtc_can_test_mode(crtc);
if (drmmode_crtc_set_mode(crtc, can_test)) {
xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
......@@ -1626,6 +1744,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
crtc->y = saved_y;
crtc->rotation = saved_rotation;
crtc->mode = saved_mode;
drmmode_create_tearfree_shadow(crtc);
} else
crtc->active = TRUE;
......@@ -1931,33 +2050,42 @@ drmmode_clear_pixmap(PixmapPtr pixmap)
}
static void *
drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
drmmode_shadow_fb_allocate(xf86CrtcPtr crtc, int width, int height,
drmmode_bo *bo, uint32_t *fb_id)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
int ret;
if (!drmmode_create_bo(drmmode, &drmmode_crtc->rotate_bo,
width, height, drmmode->kbpp)) {
if (!drmmode_create_bo(drmmode, bo, width, height, drmmode->kbpp)) {
xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
"Couldn't allocate shadow memory for rotated CRTC\n");
return NULL;
}
ret = drmmode_bo_import(drmmode, &drmmode_crtc->rotate_bo,
&drmmode_crtc->rotate_fb_id);
ret = drmmode_bo_import(drmmode, bo, fb_id);
if (ret) {
ErrorF("failed to add rotate fb\n");
drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
drmmode_bo_destroy(drmmode, bo);
return NULL;
}
#ifdef GLAMOR_HAS_GBM
if (drmmode->gbm)
return drmmode_crtc->rotate_bo.gbm;
return bo->gbm;
#endif
return drmmode_crtc->rotate_bo.dumb;
return bo->dumb;
}
static void *
drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
return drmmode_shadow_fb_allocate(crtc, width, height,
&drmmode_crtc->rotate_bo,
&drmmode_crtc->rotate_fb_id);
}
static PixmapPtr
......@@ -1983,70 +2111,91 @@ static Bool
drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo);
static PixmapPtr
drmmode_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
drmmode_shadow_fb_create(xf86CrtcPtr crtc, void *data, int width, int height,
drmmode_bo *bo, uint32_t *fb_id)
{
ScrnInfoPtr scrn = crtc->scrn;
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
uint32_t rotate_pitch;
PixmapPtr rotate_pixmap;
uint32_t pitch;
PixmapPtr pixmap;
void *pPixData = NULL;
if (!data) {
data = drmmode_shadow_allocate(crtc, width, height);
data = drmmode_shadow_fb_allocate(crtc, width, height, bo, fb_id);
if (!data) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Couldn't allocate shadow pixmap for rotated CRTC\n");
"Couldn't allocate shadow pixmap for CRTC\n");
return NULL;
}
}
if (!drmmode_bo_has_bo(&drmmode_crtc->rotate_bo)) {
if (!drmmode_bo_has_bo(bo)) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Couldn't allocate shadow pixmap for rotated CRTC\n");
"Couldn't allocate shadow pixmap for CRTC\n");
return NULL;
}
pPixData = drmmode_bo_map(drmmode, &drmmode_crtc->rotate_bo);
rotate_pitch = drmmode_bo_get_pitch(&drmmode_crtc->rotate_bo);
pPixData = drmmode_bo_map(drmmode, bo);
pitch = drmmode_bo_get_pitch(bo);
rotate_pixmap = drmmode_create_pixmap_header(scrn->pScreen,
width, height,
scrn->depth,
drmmode->kbpp,
rotate_pitch,
pPixData);
pixmap = drmmode_create_pixmap_header(scrn->pScreen,
width, height,
scrn->depth,
drmmode->kbpp,
pitch,
pPixData);
if (rotate_pixmap == NULL) {
if (pixmap == NULL) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR,
"Couldn't allocate shadow pixmap for rotated CRTC\n");
"Couldn't allocate shadow pixmap for CRTC\n");
return NULL;
}
drmmode_set_pixmap_bo(drmmode, rotate_pixmap, &drmmode_crtc->rotate_bo);
drmmode_set_pixmap_bo(drmmode, pixmap, bo);
return pixmap;
}
static PixmapPtr
drmmode_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
return rotate_pixmap;
return drmmode_shadow_fb_create(crtc, data, width, height,
&drmmode_crtc->rotate_bo,
&drmmode_crtc->rotate_fb_id);
}
static void
drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
drmmode_shadow_fb_destroy(xf86CrtcPtr crtc, PixmapPtr pixmap,
void *data, drmmode_bo *bo, uint32_t *fb_id)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
if (rotate_pixmap) {
rotate_pixmap->drawable.pScreen->DestroyPixmap(rotate_pixmap);
if (pixmap) {
pixmap->drawable.pScreen->DestroyPixmap(pixmap);
}
if (data) {
drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
drmmode_crtc->rotate_fb_id = 0;
drmModeRmFB(drmmode->fd, *fb_id);
*fb_id = 0;
drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
memset(&drmmode_crtc->rotate_bo, 0, sizeof drmmode_crtc->rotate_bo);
drmmode_bo_destroy(drmmode, bo);
memset(bo, 0, sizeof(*bo));
}
}
static void
drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr pixmap, void *data)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_shadow_fb_destroy(crtc, pixmap, data, &drmmode_crtc->rotate_bo,
&drmmode_crtc->rotate_fb_id);
}
static void
drmmode_crtc_destroy(xf86CrtcPtr crtc)
{
......@@ -2380,6 +2529,7 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res
drmmode_crtc->drmmode = drmmode;
drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
xorg_list_init(&drmmode_crtc->mode_list);
drmmode_crtc->next_msc = UINT64_MAX;
props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
DRM_MODE_OBJECT_CRTC);
......@@ -4242,6 +4392,7 @@ drmmode_free_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
dumb_bo_destroy(drmmode->fd, drmmode_crtc->cursor_bo);
drmmode_destroy_tearfree_shadow(crtc);
}
}
......
......@@ -135,6 +135,7 @@ typedef struct {
Bool async_flip_secondaries;
Bool dri2_enable;
Bool present_enable;
Bool tearfree_enable;
uint32_t vrr_prop_id;
Bool use_ctm;
......@@ -166,6 +167,19 @@ typedef struct {
uint64_t *modifiers;
} drmmode_format_rec, *drmmode_format_ptr;
typedef struct {
drmmode_bo bo;
uint32_t fb_id;
PixmapPtr px;
RegionRec dmg;
} drmmode_shadow_fb_rec, *drmmode_shadow_fb_ptr;
typedef struct {
drmmode_shadow_fb_rec buf[2];
uint32_t back_idx;
uint32_t flip_seq;
} drmmode_tearfree_rec, *drmmode_tearfree_ptr;
typedef struct {
drmmode_ptr drmmode;
drmModeCrtcPtr mode_crtc;
......@@ -184,11 +198,14 @@ typedef struct {
drmmode_bo rotate_bo;
unsigned rotate_fb_id;
drmmode_tearfree_rec tearfree;
PixmapPtr prime_pixmap;
PixmapPtr prime_pixmap_back;
unsigned prime_pixmap_x;
int src_x, src_y;
/**
* @{ MSC (vblank count) handling for the PRESENT extension.
*
......@@ -200,6 +217,8 @@ typedef struct {
uint64_t msc_high;
/** @} */
uint64_t next_msc;
Bool need_modeset;
struct xorg_list mode_list;
......@@ -308,8 +327,11 @@ void drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmmode,
int *depth, int *bpp);
void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
void drmmode_copy_damage(xf86CrtcPtr crtc, PixmapPtr dst, RegionPtr damage,
Bool empty);
int drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data);
int drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, int x, int y,
uint32_t flags, void *data);
Bool drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y);
......
......@@ -109,6 +109,21 @@ When enabled, this option allows the driver to use gamma ramps with more
entries, if supported by the kernel. By default, GAMMA_LUT will be used for
kms drivers which are known to be safe for use of GAMMA_LUT.
.TP
.BI "Option \*qTearFree\*q \*q" boolean \*q
Enable tearing prevention using the hardware page flipping mechanism.
It allocates two extra scanout buffers for each CRTC and utilizes damage
tracking to minimize buffer copying and skip unnecessary flips when the
screen's contents have not changed. It works on transformed screens too, such
as rotated and scaled CRTCs. When PageFlip is enabled, fullscreen DRI
applications will still have the discretion to not use tearing prevention.
.br
The default is
.B off.
.TP
.BI "Option \*qAtomic\*q \*q" boolean \*q
Enable atomic modesetting when supported. The default is
.B off.
.TP
.SH "SEE ALSO"
@xservername@(@appmansuffix@), @xconfigfile@(@filemansuffix@), Xserver(@appmansuffix@),
X(@miscmansuffix@)
......
......@@ -35,8 +35,8 @@
* Returns a negative value on error, 0 if there was nothing to process,
* or 1 if we handled any events.
*/
int
ms_flush_drm_events(ScreenPtr screen)
static int
ms_flush_drm_events_timeout(ScreenPtr screen, int timeout)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
modesettingPtr ms = modesettingPTR(scrn);
......@@ -45,7 +45,7 @@ ms_flush_drm_events(ScreenPtr screen)
int r;
do {
r = xserver_poll(&p, 1, 0);
r = xserver_poll(&p, 1, timeout);
} while (r == -1 && (errno == EINTR || errno == EAGAIN));
/* If there was an error, r will be < 0. Return that. If there was
......@@ -63,6 +63,12 @@ ms_flush_drm_events(ScreenPtr screen)
return 1;
}
int
ms_flush_drm_events(ScreenPtr screen)
{
return ms_flush_drm_events_timeout(screen, 0);
}
#ifdef GLAMOR_HAS_GBM
/*
......@@ -160,11 +166,32 @@ ms_pageflip_abort(void *data)
}
static Bool
do_queue_flip_on_crtc(modesettingPtr ms, xf86CrtcPtr crtc,
uint32_t flags, uint32_t seq)
do_queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc, uint32_t flags,
uint32_t seq, uint32_t fb_id, int x, int y)
{
return drmmode_crtc_flip(crtc, ms->drmmode.fb_id, flags,
(void *) (uintptr_t) seq);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
while (drmmode_crtc_flip(crtc, fb_id, x, y, flags, (void *)(long)seq)) {
/* We may have failed because the event queue was full. Flush it
* and retry. If there was nothing to flush, then we failed for
* some other reason and should just return an error.
*/
if (ms_flush_drm_events(screen) <= 0) {
/* The failure could be caused by a pending TearFree flip, in which
* case we should wait until there's a new event and try again.
*/
if (!trf->flip_seq || ms_flush_drm_events_timeout(screen, -1) < 0) {
ms_drm_abort_seq(crtc->scrn, seq);
return TRUE;
}
}
/* We flushed some events, so try again. */
xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING, "flip queue retry\n");
}
return FALSE;
}
enum queue_flip_status {
......@@ -205,20 +232,9 @@ queue_flip_on_crtc(ScreenPtr screen, xf86CrtcPtr crtc,
/* take a reference on flipdata for use in flip */
flipdata->flip_count++;
while (do_queue_flip_on_crtc(ms, crtc, flags, seq)) {
/* We may have failed because the event queue was full. Flush it
* and retry. If there was nothing to flush, then we failed for
* some other reason and should just return an error.
*/
if (ms_flush_drm_events(screen) <= 0) {
/* Aborting will also decrement flip_count and free(flip). */
ms_drm_abort_seq(scrn, seq);
return QUEUE_FLIP_DRM_FLUSH_FAILED;
}
/* We flushed some events, so try again. */
xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue retry\n");
}
if (do_queue_flip_on_crtc(screen, crtc, flags, seq, ms->drmmode.fb_id,
crtc->x, crtc->y))
return QUEUE_FLIP_DRM_FLUSH_FAILED;
/* The page flip succeeded. */
return QUEUE_FLIP_SUCCESS;
......@@ -465,4 +481,50 @@ error_out:
#endif /* GLAMOR_HAS_GBM */
}
static void
ms_tearfree_flip_abort(void *data)
{
drmmode_tearfree_ptr trf = data;
trf->flip_seq = 0;
}
static void
ms_tearfree_flip_handler(uint64_t msc, uint64_t usec, void *data)
{
drmmode_tearfree_ptr trf = data;
/* Swap the buffers and complete the flip */
trf->back_idx ^= 1;
trf->flip_seq = 0;
}
Bool
ms_do_tearfree_flip(ScreenPtr screen, xf86CrtcPtr crtc)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
uint32_t idx = trf->back_idx, seq;
seq = ms_drm_queue_alloc(crtc, trf, ms_tearfree_flip_handler,
ms_tearfree_flip_abort);
if (!seq)
goto no_flip;
/* Copy the damage to the back buffer and then flip it at the vblank */
drmmode_copy_damage(crtc, trf->buf[idx].px, &trf->buf[idx].dmg, TRUE);
if (do_queue_flip_on_crtc(screen, crtc, DRM_MODE_PAGE_FLIP_EVENT,
seq, trf->buf[idx].fb_id, 0, 0))
goto no_flip;
trf->flip_seq = seq;
return FALSE;
no_flip:
xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING,
"TearFree flip failed, rendering frame without TearFree\n");
drmmode_copy_damage(crtc, trf->buf[idx ^ 1].px,
&trf->buf[idx ^ 1].dmg, FALSE);
return TRUE;
}
#endif
......@@ -318,14 +318,32 @@ ms_present_check_flip(RRCrtcPtr crtc,
modesettingPtr ms = modesettingPTR(scrn);
if (ms->drmmode.sprites_visible > 0)
return FALSE;
goto no_flip;
if(!ms_present_check_unflip(crtc, window, pixmap, sync_flip, reason))
return FALSE;
goto no_flip;
ms->flip_window = window;
return TRUE;
no_flip:
/* Export some info about TearFree if Present can't flip anyway */
if (reason && ms->drmmode.tearfree_enable) {
xf86CrtcPtr xf86_crtc = crtc->devPrivate;
drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
drmmode_tearfree_ptr trf = &drmmode_crtc->tearfree;
if (trf->buf[0].px) {
if (trf->flip_seq)
/* The driver has a TearFree flip pending */
*reason = PRESENT_FLIP_REASON_DRIVER_TEARFREE_FLIPPING;
else
/* The driver uses TearFree flips and there's no flip pending */
*reason = PRESENT_FLIP_REASON_DRIVER_TEARFREE;
}
}
return FALSE;
}
/*
......
......@@ -260,6 +260,51 @@ ms_get_kernel_ust_msc(xf86CrtcPtr crtc,
}
}
static void
ms_drm_set_seq_msc(uint32_t seq, uint64_t msc)
{
struct ms_drm_queue *q;
xorg_list_for_each_entry(q, &ms_drm_queue, list) {
if (q->seq == seq) {
q->msc = msc;
break;
}
}
}
static void
ms_drm_set_seq_queued(uint32_t seq, uint64_t msc)
{
drmmode_crtc_private_ptr drmmode_crtc;
struct ms_drm_queue *q;
xorg_list_for_each_entry(q, &ms_drm_queue, list) {
if (q->seq == seq) {
drmmode_crtc = q->crtc->driver_private;
if (msc < drmmode_crtc->next_msc)
drmmode_crtc->next_msc = msc;
q->msc = msc;
q->kernel_queued = TRUE;
break;
}
}
}
static Bool
ms_queue_coalesce(xf86CrtcPtr crtc, uint32_t seq, uint64_t msc)
{
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
/* If the next MSC is too late, then this event can't be coalesced */
if (msc < drmmode_crtc->next_msc)
return FALSE;
/* Set the target MSC on this sequence number */
ms_drm_set_seq_msc(seq, msc);
return TRUE;
}
Bool
ms_queue_vblank(xf86CrtcPtr crtc, ms_queue_flag flags,
uint64_t msc, uint64_t *msc_queued, uint32_t seq)
......@@ -271,6 +316,10 @@ ms_queue_vblank(xf86CrtcPtr crtc, ms_queue_flag flags,
drmVBlank vbl;
int ret;
/* Try coalescing this event into another to avoid event queue exhaustion */
if (flags == MS_QUEUE_ABSOLUTE && ms_queue_coalesce(crtc, seq, msc))
return TRUE;
for (;;) {
/* Queue an event at the specified sequence */
if (ms->has_queue_sequence || !ms->tried_queue_sequence) {
......@@ -287,8 +336,10 @@ ms_queue_vblank(xf86CrtcPtr crtc, ms_queue_flag flags,
ret = drmCrtcQueueSequence(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
drm_flags, msc, &kernel_queued, seq);
if (ret == 0) {
msc = ms_kernel_msc_to_crtc_msc(crtc, kernel_queued, TRUE);
ms_drm_set_seq_queued(seq, msc);
if (msc_queued)
*msc_queued = ms_kernel_msc_to_crtc_msc(crtc, kernel_queued, TRUE);
*msc_queued = msc;
ms->has_queue_sequence = TRUE;
return TRUE;
}
......@@ -310,8 +361,10 @@ ms_queue_vblank(xf86CrtcPtr crtc, ms_queue_flag flags,
vbl.request.signal = seq;
ret = drmWaitVBlank(ms->fd, &vbl);
if (ret == 0) {
msc = ms_kernel_msc_to_crtc_msc(crtc, vbl.reply.sequence, FALSE);
ms_drm_set_seq_queued(seq, msc);
if (msc_queued)
*msc_queued = ms_kernel_msc_to_crtc_msc(crtc, vbl.reply.sequence, FALSE);
*msc_queued = msc;
return TRUE;
}
check:
......@@ -418,13 +471,15 @@ ms_drm_queue_alloc(xf86CrtcPtr crtc,
if (!ms_drm_seq)
++ms_drm_seq;
q->seq = ms_drm_seq++;
q->msc = UINT64_MAX;
q->scrn = scrn;
q->crtc = crtc;
q->data = data;
q->handler = handler;
q->abort = abort;
xorg_list_add(&q->list, &ms_drm_queue);
/* Keep the list formatted in ascending order of sequence number */
xorg_list_append(&q->list, &ms_drm_queue);
return q->seq;
}
......@@ -437,9 +492,18 @@ ms_drm_queue_alloc(xf86CrtcPtr crtc,
static void
ms_drm_abort_one(struct ms_drm_queue *q)
{
if (q->aborted)
return;
/* Don't remove vblank events if they were queued in the kernel */
if (q->kernel_queued) {
q->abort(q->data);
q->aborted = TRUE;
} else {
xorg_list_del(&q->list);
q->abort(q->data);
free(q);
}
}
/**
......@@ -500,18 +564,61 @@ ms_drm_sequence_handler(int fd, uint64_t frame, uint64_t ns, Bool is64bit, uint6
{
struct ms_drm_queue *q, *tmp;
uint32_t seq = (uint32_t) user_data;
xf86CrtcPtr crtc = NULL;
drmmode_crtc_private_ptr drmmode_crtc;
uint64_t msc, next_msc = UINT64_MAX;
xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) {
/* Handle the seq for this event first in order to get the CRTC */
xorg_list_for_each_entry(q, &ms_drm_queue, list) {
if (q->seq == seq) {
uint64_t msc;
msc = ms_kernel_msc_to_crtc_msc(q->crtc, frame, is64bit);
crtc = q->crtc;
msc = ms_kernel_msc_to_crtc_msc(crtc, frame, is64bit);
xorg_list_del(&q->list);
q->handler(msc, ns / 1000, q->data);
if (!q->aborted)
q->handler(msc, ns / 1000, q->data);
free(q);
break;
}
}
if (!crtc)
return;
/* Now run all of the vblank events for this CRTC with an expired MSC */
xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) {
if (q->crtc == crtc && q->msc <= msc) {
xorg_list_del(&q->list);
if (!q->aborted)
q->handler(msc, ns / 1000, q->data);
free(q);
}
}
/* Find this CRTC's next queued MSC and next non-queued MSC to be handled */
msc = UINT64_MAX;
xorg_list_for_each_entry(q, &ms_drm_queue, list) {
if (q->crtc == crtc) {
if (q->kernel_queued) {
if (q->msc < next_msc)
next_msc = q->msc;
} else if (q->msc < msc) {
msc = q->msc;
seq = q->seq;
}
}
}
/* Queue an event if the next queued MSC isn't soon enough */
drmmode_crtc = crtc->driver_private;
drmmode_crtc->next_msc = next_msc;
if (msc < next_msc && !ms_queue_vblank(crtc, MS_QUEUE_ABSOLUTE, msc, NULL, seq)) {
xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING,
"failed to queue next vblank event, aborting lost events\n");
xorg_list_for_each_entry_safe(q, tmp, &ms_drm_queue, list) {
if (q->crtc == crtc && q->msc < next_msc)
ms_drm_abort_one(q);
}
}
}
static void
......
......@@ -912,6 +912,11 @@ extern _X_EXPORT void
extern _X_EXPORT Bool
xf86CrtcRotate(xf86CrtcPtr crtc);
extern _X_EXPORT void
xf86RotateCrtcRedisplay(xf86CrtcPtr crtc, PixmapPtr dst_pixmap,
DrawableRec *src_drawable, RegionPtr region,
Bool transform_src);
/*
* Clean up any rotation data, used when a crtc is turned off
* as well as when rotation is disabled.
......
......@@ -39,13 +39,13 @@
#include "X11/extensions/dpmsconst.h"
#include "X11/Xatom.h"
static void
xf86RotateCrtcRedisplay(xf86CrtcPtr crtc, RegionPtr region)
void
xf86RotateCrtcRedisplay(xf86CrtcPtr crtc, PixmapPtr dst_pixmap,
DrawableRec *src_drawable, RegionPtr region,
Bool transform_src)
{
ScrnInfoPtr scrn = crtc->scrn;
ScreenPtr screen = scrn->pScreen;
WindowPtr root = screen->root;
PixmapPtr dst_pixmap = crtc->rotatedPixmap;
PictFormatPtr format = PictureWindowFormat(screen->root);
int error;
PicturePtr src, dst;
......@@ -57,7 +57,7 @@ xf86RotateCrtcRedisplay(xf86CrtcPtr crtc, RegionPtr region)
return;
src = CreatePicture(None,
&root->drawable,
src_drawable,
format,
CPSubwindowMode,
&include_inferiors, serverClient, &error);
......@@ -70,9 +70,11 @@ xf86RotateCrtcRedisplay(xf86CrtcPtr crtc, RegionPtr region)
if (!dst)
return;
error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);
if (error)
return;
if (transform_src) {
error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);
if (error)
return;
}
if (crtc->transform_in_use && crtc->filter)
SetPicturePictFilter(src, crtc->filter, crtc->params, crtc->nparams);
......@@ -205,7 +207,9 @@ xf86RotateRedisplay(ScreenPtr pScreen)
/* update damaged region */
if (RegionNotEmpty(&crtc_damage))
xf86RotateCrtcRedisplay(crtc, &crtc_damage);
xf86RotateCrtcRedisplay(crtc, crtc->rotatedPixmap,
&pScreen->root->drawable,
&crtc_damage, TRUE);
RegionUninit(&crtc_damage);
}
......
......@@ -626,6 +626,9 @@ main(int argc, char **argv, char **envp)
mach_port_t mp;
kern_return_t kr;
/* Ignore SIGPIPE */
signal(SIGPIPE, SIG_IGN);
/* Setup our environment for our children */
setup_env();
......
......@@ -45,10 +45,6 @@
#include <dispatch/dispatch.h>
#ifdef DEBUG_XP_LOCK_WINDOW
#include <execinfo.h>
#endif
#define DEFINE_ATOM_HELPER(func, atom_name) \
static Atom func(void) { \
static int generation; \
......@@ -353,15 +349,8 @@ xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow)
xp_error err;
#ifdef DEBUG_XP_LOCK_WINDOW
void* callstack[128];
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
ErrorF("=== LOCK %d ===\n", (int)x_cvt_vptr_to_uint(wid));
for (i = 0; i < frames; ++i) {
ErrorF(" %s\n", strs[i]);
}
free(strs);
xorg_backtrace();
#endif
err = xp_lock_window(x_cvt_vptr_to_uint(
......@@ -371,6 +360,10 @@ xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow)
(int)x_cvt_vptr_to_uint(
wid), (int)err);
#ifdef DEBUG_XP_LOCK_WINDOW
ErrorF(" bits: %p\n", *data);
#endif
*pixelData = data[0];
*bytesPerRow = rowbytes[0];
}
......@@ -384,15 +377,8 @@ xprStopDrawing(RootlessFrameID wid, Bool flush)
xp_error err;
#ifdef DEBUG_XP_LOCK_WINDOW
void* callstack[128];
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
ErrorF("=== UNLOCK %d ===\n", (int)x_cvt_vptr_to_uint(wid));
for (i = 0; i < frames; ++i) {
ErrorF(" %s\n", strs[i]);
}
free(strs);
xorg_backtrace();
#endif
err = xp_unlock_window(x_cvt_vptr_to_uint(wid), flush);
......
......@@ -47,6 +47,7 @@ viewporter_xml = join_paths(protodir, 'stable', 'viewporter', 'viewporter.xml')
xdg_shell_xml = join_paths(protodir, 'stable', 'xdg-shell', 'xdg-shell.xml')
drm_lease_xml = join_paths(protodir, 'staging', 'drm-lease', 'drm-lease-v1.xml')
shortcuts_inhibit_xml = join_paths(protodir, 'unstable', 'keyboard-shortcuts-inhibit', 'keyboard-shortcuts-inhibit-unstable-v1.xml')
xwayland_shell_xml = join_paths(protodir, 'staging', 'xwayland-shell', 'xwayland-shell-v1.xml')
client_header = generator(scanner,
output : '@BASENAME@-client-protocol.h',
......@@ -74,6 +75,7 @@ srcs += client_header.process(viewporter_xml)
srcs += client_header.process(xdg_shell_xml)
srcs += client_header.process(drm_lease_xml)
srcs += client_header.process(shortcuts_inhibit_xml)
srcs += client_header.process(xwayland_shell_xml)
srcs += code.process(relative_xml)
srcs += code.process(pointer_xml)
srcs += code.process(gestures_xml)
......@@ -85,6 +87,7 @@ srcs += code.process(viewporter_xml)
srcs += code.process(xdg_shell_xml)
srcs += code.process(drm_lease_xml)
srcs += code.process(shortcuts_inhibit_xml)
srcs += code.process(xwayland_shell_xml)
xwayland_glamor = []
eglstream_srcs = []
......
......@@ -59,6 +59,7 @@
#include "xdg-output-unstable-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "xdg-shell-client-protocol.h"
#include "xwayland-shell-v1-client-protocol.h"
static DevPrivateKeyRec xwl_screen_private_key;
static DevPrivateKeyRec xwl_client_private_key;
......@@ -451,6 +452,10 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
else if (strcmp(interface, "wp_viewporter") == 0) {
xwl_screen->viewporter = wl_registry_bind(registry, id, &wp_viewporter_interface, 1);
}
else if (strcmp(interface, "xwayland_shell_v1") == 0 && xwl_screen->rootless) {
xwl_screen->xwayland_shell =
wl_registry_bind(registry, id, &xwayland_shell_v1_interface, 1);
}
#ifdef XWL_HAS_GLAMOR
else if (xwl_screen->glamor) {
xwl_glamor_init_wl_registry(xwl_screen, registry, id, interface,
......
......@@ -103,11 +103,13 @@ struct xwl_screen {
struct zwp_linux_dmabuf_v1 *dmabuf;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct wp_viewporter *viewporter;
struct xwayland_shell_v1 *xwayland_shell;
struct xorg_list drm_lease_devices;
struct xorg_list queued_drm_lease_devices;
struct xorg_list drm_leases;
struct xwl_output *fixed_output;
struct xorg_list pending_wl_surface_destroy;
uint64_t surface_association_serial;
uint32_t serial;
#define XWL_FORMAT_ARGB8888 (1 << 0)
......
......@@ -45,6 +45,7 @@
#include "viewporter-client-protocol.h"
#include "xdg-shell-client-protocol.h"
#include "xwayland-shell-v1-client-protocol.h"
#define DELAYED_WL_SURFACE_DESTROY 1000 /* ms */
......@@ -438,24 +439,30 @@ xwl_window_init_allow_commits(struct xwl_window *xwl_window)
xwl_window_set_allow_commits(xwl_window, TRUE, "no property");
}
static uint32_t
serial_lo(uint64_t value)
{
return value & 0xFFFFFFFFu;
}
static uint32_t
serial_hi(uint64_t value)
{
return value >> 32u;
}
static void
send_surface_id_event(struct xwl_window *xwl_window)
send_window_client_message(struct xwl_window *xwl_window, Atom type_atom, uint64_t value)
{
static const char atom_name[] = "WL_SURFACE_ID";
static Atom type_atom;
DeviceIntPtr dev;
xEvent e;
if (type_atom == None)
type_atom = MakeAtom(atom_name, strlen(atom_name), TRUE);
e.u.u.type = ClientMessage;
e.u.u.detail = 32;
e.u.clientMessage.window = xwl_window->window->drawable.id;
e.u.clientMessage.u.l.type = type_atom;
e.u.clientMessage.u.l.longs0 =
wl_proxy_get_id((struct wl_proxy *) xwl_window->surface);
e.u.clientMessage.u.l.longs1 = 0;
e.u.clientMessage.u.l.longs0 = serial_lo(value);
e.u.clientMessage.u.l.longs1 = serial_hi(value);
e.u.clientMessage.u.l.longs2 = 0;
e.u.clientMessage.u.l.longs3 = 0;
e.u.clientMessage.u.l.longs4 = 0;
......@@ -465,6 +472,54 @@ send_surface_id_event(struct xwl_window *xwl_window)
&e, 1, SubstructureRedirectMask, NullGrab);
}
static void
send_surface_id_event_serial(struct xwl_window *xwl_window)
{
static const char atom_name[] = "WL_SURFACE_SERIAL";
static Atom type_atom;
uint64_t serial;
if (type_atom == None)
type_atom = MakeAtom(atom_name, strlen(atom_name), TRUE);
serial = ++xwl_window->xwl_screen->surface_association_serial;
send_window_client_message(xwl_window, type_atom, serial);
xwayland_surface_v1_set_serial(xwl_window->xwayland_surface,
serial_lo(serial), serial_hi(serial));
wl_surface_commit(xwl_window->surface);
/* Flush wayland display *after* commit in the new path. */
wl_display_flush(xwl_window->xwl_screen->display);
}
static void
send_surface_id_event_legacy(struct xwl_window *xwl_window)
{
static const char atom_name[] = "WL_SURFACE_ID";
static Atom type_atom;
uint32_t surface_id;
if (type_atom == None)
type_atom = MakeAtom(atom_name, strlen(atom_name), TRUE);
surface_id = wl_proxy_get_id((struct wl_proxy *) xwl_window->surface);
/* Flush wayland display *before* setting the atom in the legacy path */
wl_display_flush(xwl_window->xwl_screen->display);
send_window_client_message(xwl_window, type_atom, (uint64_t)surface_id);
}
static void
send_surface_id_event(struct xwl_window *xwl_window)
{
return xwl_window->xwayland_surface
? send_surface_id_event_serial(xwl_window)
: send_surface_id_event_legacy(xwl_window);
}
static Bool
xwl_window_set_fullscreen(struct xwl_window *xwl_window)
{
......@@ -772,11 +827,14 @@ ensure_surface_for_window(WindowPtr window)
goto err;
}
if (xwl_screen->xwayland_shell) {
xwl_window->xwayland_surface = xwayland_shell_v1_get_xwayland_surface(
xwl_screen->xwayland_shell, xwl_window->surface);
}
if (!xwl_screen->rootless && !xwl_create_root_surface(xwl_window))
goto err;
wl_display_flush(xwl_screen->display);
send_surface_id_event(xwl_window);
wl_surface_set_user_data(xwl_window->surface, xwl_window);
......@@ -889,7 +947,7 @@ xwl_surface_destroy_callback(OsTimerPtr timer, CARD32 now, void *arg)
}
static void
release_wl_surface_for_window(struct xwl_window *xwl_window)
release_wl_surface_for_window_legacy_delay(struct xwl_window *xwl_window)
{
struct xwl_wl_surface *xwl_wl_surface;
......@@ -916,6 +974,22 @@ release_wl_surface_for_window(struct xwl_window *xwl_window)
xwl_surface_destroy_callback, xwl_wl_surface);
}
static void
release_wl_surface_for_window_shell(struct xwl_window *xwl_window)
{
xwayland_surface_v1_destroy(xwl_window->xwayland_surface);
wl_surface_destroy(xwl_window->surface);
}
static void
release_wl_surface_for_window(struct xwl_window *xwl_window)
{
if (xwl_window->xwayland_surface)
release_wl_surface_for_window_shell(xwl_window);
else
release_wl_surface_for_window_legacy_delay(xwl_window);
}
Bool
xwl_unrealize_window(WindowPtr window)
{
......