present: Send PresentCompleteModeSuboptimalCopy appropriately

Add 'check_flip2' hook for driver to let know the core
about why flipping is not possible ('reason').
If it is because of unsupported buffer format/modifier,
a PresentCompleteNotify event is sent to the client with
the PresentCompleteModeSuboptimalCopy mode.

v2: Check for PresentOptionSuboptimal and check driver version
    before using 'check_flip2'.

v3: Only require one of 'check_flip' or 'check_flip2' to be
    implemented by the driver.
    Refactor reasons list to enum

Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb@collabora.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Acked-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
Louis-Francis Ratté-Boulianne 2018-02-28 01:19:36 +00:00 committed by Adam Jackson
parent 6e7c40f62d
commit e2ef3b44fa
6 changed files with 50 additions and 20 deletions

View File

@ -753,7 +753,7 @@ DAMAGEPROTO="damageproto >= 1.1"
XCMISCPROTO="xcmiscproto >= 1.2.0" XCMISCPROTO="xcmiscproto >= 1.2.0"
BIGREQSPROTO="bigreqsproto >= 1.1.0" BIGREQSPROTO="bigreqsproto >= 1.1.0"
XTRANS="xtrans >= 1.3.5" XTRANS="xtrans >= 1.3.5"
PRESENTPROTO="presentproto >= 1.0" PRESENTPROTO="presentproto >= 1.1"
dnl List of libraries that require a specific version dnl List of libraries that require a specific version
LIBAPPLEWM="applewm >= 1.4" LIBAPPLEWM="applewm >= 1.4"

View File

@ -69,7 +69,7 @@
/* Present */ /* Present */
#define SERVER_PRESENT_MAJOR_VERSION 1 #define SERVER_PRESENT_MAJOR_VERSION 1
#define SERVER_PRESENT_MINOR_VERSION 0 #define SERVER_PRESENT_MINOR_VERSION 1
/* RandR */ /* RandR */
#define SERVER_RANDR_MAJOR_VERSION 1 #define SERVER_RANDR_MAJOR_VERSION 1

View File

@ -13,7 +13,7 @@ libxserver_present = static_library('libxserver_present',
include_directories: inc, include_directories: inc,
dependencies: [ dependencies: [
common_dep, common_dep,
dependency('presentproto', version: '>= 1.0') dependency('presentproto', version: '>= 1.1')
], ],
c_args: '-DHAVE_XORG_CONFIG_H' c_args: '-DHAVE_XORG_CONFIG_H'
) )

View File

@ -118,19 +118,23 @@ present_flip_pending_pixmap(ScreenPtr screen)
} }
static Bool static Bool
present_check_flip(RRCrtcPtr crtc, present_check_flip(RRCrtcPtr crtc,
WindowPtr window, WindowPtr window,
PixmapPtr pixmap, PixmapPtr pixmap,
Bool sync_flip, Bool sync_flip,
RegionPtr valid, RegionPtr valid,
int16_t x_off, int16_t x_off,
int16_t y_off) int16_t y_off,
PresentFlipReason *reason)
{ {
ScreenPtr screen = window->drawable.pScreen; ScreenPtr screen = window->drawable.pScreen;
PixmapPtr window_pixmap; PixmapPtr window_pixmap;
WindowPtr root = screen->root; WindowPtr root = screen->root;
present_screen_priv_ptr screen_priv = present_screen_priv(screen); present_screen_priv_ptr screen_priv = present_screen_priv(screen);
if (reason)
*reason = PRESENT_FLIP_REASON_UNKNOWN;
if (!screen_priv) if (!screen_priv)
return FALSE; return FALSE;
@ -177,7 +181,12 @@ present_check_flip(RRCrtcPtr crtc,
} }
/* Ask the driver for permission */ /* Ask the driver for permission */
if (screen_priv->info->check_flip) { if (screen_priv->info->version >= 1 && screen_priv->info->check_flip2) {
if (!(*screen_priv->info->check_flip2) (crtc, window, pixmap, sync_flip, reason)) {
DebugPresent(("\td %08lx -> %08lx\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
return FALSE;
}
} else if (screen_priv->info->check_flip) {
if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) { if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
DebugPresent(("\td %08lx -> %08lx\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0)); DebugPresent(("\td %08lx -> %08lx\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
return FALSE; return FALSE;
@ -564,6 +573,7 @@ present_check_flip_window (WindowPtr window)
present_window_priv_ptr window_priv = present_window_priv(window); present_window_priv_ptr window_priv = present_window_priv(window);
present_vblank_ptr flip_pending = screen_priv->flip_pending; present_vblank_ptr flip_pending = screen_priv->flip_pending;
present_vblank_ptr vblank; present_vblank_ptr vblank;
PresentFlipReason reason;
/* If this window hasn't ever been used with Present, it can't be /* If this window hasn't ever been used with Present, it can't be
* flipping * flipping
@ -580,7 +590,7 @@ present_check_flip_window (WindowPtr window)
*/ */
if (flip_pending->window == window) { if (flip_pending->window == window) {
if (!present_check_flip(flip_pending->crtc, window, flip_pending->pixmap, if (!present_check_flip(flip_pending->crtc, window, flip_pending->pixmap,
flip_pending->sync_flip, NULL, 0, 0)) flip_pending->sync_flip, NULL, 0, 0, NULL))
present_set_abort_flip(screen); present_set_abort_flip(screen);
} }
} else { } else {
@ -588,15 +598,16 @@ present_check_flip_window (WindowPtr window)
* Check current flip * Check current flip
*/ */
if (window == screen_priv->flip_window) { if (window == screen_priv->flip_window) {
if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0)) if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0, NULL))
present_unflip(screen); present_unflip(screen);
} }
} }
/* Now check any queued vblanks */ /* Now check any queued vblanks */
xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) { xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0)) { if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0, &reason)) {
vblank->flip = FALSE; vblank->flip = FALSE;
vblank->reason = reason;
if (vblank->sync_flip) if (vblank->sync_flip)
vblank->requeue = TRUE; vblank->requeue = TRUE;
} }
@ -756,10 +767,14 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
/* Compute correct CompleteMode /* Compute correct CompleteMode
*/ */
if (vblank->kind == PresentCompleteKindPixmap) { if (vblank->kind == PresentCompleteKindPixmap) {
if (vblank->pixmap && vblank->window) if (vblank->pixmap && vblank->window) {
mode = PresentCompleteModeCopy; if (vblank->has_suboptimal && vblank->reason == PRESENT_FLIP_REASON_BUFFER_FORMAT)
else mode = PresentCompleteModeSuboptimalCopy;
else
mode = PresentCompleteModeCopy;
} else {
mode = PresentCompleteModeSkip; mode = PresentCompleteModeSkip;
}
} }
else else
mode = PresentCompleteModeCopy; mode = PresentCompleteModeCopy;
@ -795,6 +810,7 @@ present_pixmap(WindowPtr window,
ScreenPtr screen = window->drawable.pScreen; ScreenPtr screen = window->drawable.pScreen;
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE); present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
present_screen_priv_ptr screen_priv = present_screen_priv(screen); present_screen_priv_ptr screen_priv = present_screen_priv(screen);
PresentFlipReason reason = PRESENT_FLIP_REASON_UNKNOWN;
if (!window_priv) if (!window_priv)
return BadAlloc; return BadAlloc;
@ -912,22 +928,24 @@ present_pixmap(WindowPtr window,
vblank->msc_offset = window_priv->msc_offset; vblank->msc_offset = window_priv->msc_offset;
vblank->notifies = notifies; vblank->notifies = notifies;
vblank->num_notifies = num_notifies; vblank->num_notifies = num_notifies;
vblank->has_suboptimal = (options & PresentOptionSuboptimal);
if (pixmap != NULL && if (pixmap != NULL &&
!(options & PresentOptionCopy) && !(options & PresentOptionCopy) &&
screen_priv->info) { screen_priv->info) {
if (msc_is_after(target_msc, crtc_msc) && if (msc_is_after(target_msc, crtc_msc) &&
present_check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off)) present_check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off, &reason))
{ {
vblank->flip = TRUE; vblank->flip = TRUE;
vblank->sync_flip = TRUE; vblank->sync_flip = TRUE;
target_msc--; target_msc--;
} else if ((screen_priv->info->capabilities & PresentCapabilityAsync) && } else if ((screen_priv->info->capabilities & PresentCapabilityAsync) &&
present_check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off)) present_check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off, &reason))
{ {
vblank->flip = TRUE; vblank->flip = TRUE;
} }
} }
vblank->reason = reason;
if (wait_fence) { if (wait_fence) {
vblank->wait_fence = present_fence_create(wait_fence); vblank->wait_fence = present_fence_create(wait_fence);

View File

@ -27,6 +27,11 @@
#include "randrstr.h" #include "randrstr.h"
#include "presentext.h" #include "presentext.h"
typedef enum {
PRESENT_FLIP_REASON_UNKNOWN,
PRESENT_FLIP_REASON_BUFFER_FORMAT
} PresentFlipReason;
typedef struct present_vblank present_vblank_rec, *present_vblank_ptr; typedef struct present_vblank present_vblank_rec, *present_vblank_ptr;
/* Return the current CRTC for 'window'. /* Return the current CRTC for 'window'.
@ -59,6 +64,10 @@ typedef void (*present_flush_ptr) (WindowPtr window);
*/ */
typedef Bool (*present_check_flip_ptr) (RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip); typedef Bool (*present_check_flip_ptr) (RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip);
/* Same as 'check_flip' but it can return a 'reason' why the flip would fail.
*/
typedef Bool (*present_check_flip2_ptr) (RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, Bool sync_flip, PresentFlipReason *reason);
/* Flip pixmap, return false if it didn't happen. /* Flip pixmap, return false if it didn't happen.
* *
* 'crtc' is to be used for any necessary synchronization. * 'crtc' is to be used for any necessary synchronization.
@ -83,7 +92,7 @@ typedef Bool (*present_flip_ptr) (RRCrtcPtr crtc,
typedef void (*present_unflip_ptr) (ScreenPtr screen, typedef void (*present_unflip_ptr) (ScreenPtr screen,
uint64_t event_id); uint64_t event_id);
#define PRESENT_SCREEN_INFO_VERSION 0 #define PRESENT_SCREEN_INFO_VERSION 1
typedef struct present_screen_info { typedef struct present_screen_info {
uint32_t version; uint32_t version;
@ -97,6 +106,7 @@ typedef struct present_screen_info {
present_check_flip_ptr check_flip; present_check_flip_ptr check_flip;
present_flip_ptr flip; present_flip_ptr flip;
present_unflip_ptr unflip; present_unflip_ptr unflip;
present_check_flip2_ptr check_flip2;
} present_screen_info_rec, *present_screen_info_ptr; } present_screen_info_rec, *present_screen_info_ptr;

View File

@ -75,6 +75,8 @@ struct present_vblank {
Bool flip_ready; /* wants to flip, but waiting for previous flip or unflip */ Bool flip_ready; /* wants to flip, but waiting for previous flip or unflip */
Bool sync_flip; /* do flip synchronous to vblank */ Bool sync_flip; /* do flip synchronous to vblank */
Bool abort_flip; /* aborting this flip */ Bool abort_flip; /* aborting this flip */
PresentFlipReason reason; /* reason for which flip is not possible */
Bool has_suboptimal; /* whether client can support SuboptimalCopy mode */
}; };
typedef struct present_screen_priv { typedef struct present_screen_priv {