Skip to content

Commit 09f66cd

Browse files
committed
enhancement: implementing page flip for fullscreen applications.
1 parent b69d0b4 commit 09f66cd

File tree

2 files changed

+126
-50
lines changed

2 files changed

+126
-50
lines changed

app/src/main/cpp/lorie/InitOutput.c

+88-25
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "micmap.h"
2929
#include "miline.h"
3030
#include "shmint.h"
31+
#include "present_priv.h"
3132
#include "misyncshm.h"
3233
#include "glxserver.h"
3334
#include "glxutil.h"
@@ -50,6 +51,7 @@ extern DeviceIntPtr lorieMouse, lorieKeyboard;
5051
struct vblank {
5152
struct xorg_list link;
5253
uint64_t id, msc;
54+
bool flip;
5355
};
5456

5557
static struct present_screen_info loriePresentInfo;
@@ -60,6 +62,7 @@ typedef struct {
6062
DamagePtr damage;
6163
OsTimerPtr fpsTimer;
6264

65+
SetWindowPixmapProcPtr SetWindowPixmap;
6366
CloseScreenProcPtr CloseScreen;
6467

6568
int eventFd, stateFd;
@@ -94,7 +97,7 @@ static char *xstartup = NULL;
9497

9598
typedef struct {
9699
LorieBuffer *buffer;
97-
bool flipped, imported;
100+
bool flipped, wasLocked;
98101
void *locked;
99102
void *mem;
100103
} LoriePixmapPriv;
@@ -392,14 +395,16 @@ static miPointerScreenFuncRec loriePointerCursorFuncs = {
392395
.WarpCursor = miPointerWarpCursor
393396
};
394397

395-
static void loriePerformVblanks(void);
398+
static void loriePerformVblanks(bool);
396399

397400
static Bool lorieRedraw(__unused ClientPtr pClient, __unused void *closure) {
398401
int status, nonEmpty;
399402
LoriePixmapPriv* priv;
400403
PixmapPtr root = pScreenPtr && pScreenPtr->root ? pScreenPtr->GetWindowPixmap(pScreenPtr->root) : NULL;
401404

402-
loriePerformVblanks();
405+
pvfb->current_msc++;
406+
loriePerformVblanks(true);
407+
loriePerformVblanks(false);
403408

404409
pvfb->state->waitForNextFrame = false;
405410

@@ -419,10 +424,12 @@ static Bool lorieRedraw(__unused ClientPtr pClient, __unused void *closure) {
419424
// and this is not needed. But according to docs we should do it for any case.
420425
// Also according to AHardwareBuffer docs simultaneous reading in rendering thread and
421426
// locking for writing in other thread is fine.
422-
LorieBuffer_unlock(priv->buffer);
423-
status = LorieBuffer_lock(priv->buffer, &priv->locked);
424-
if (status)
425-
FatalError("Failed to lock the surface: %d\n", status);
427+
if (priv->locked) {
428+
LorieBuffer_unlock(priv->buffer);
429+
status = LorieBuffer_lock(priv->buffer, &priv->locked);
430+
if (status)
431+
FatalError("Failed to lock the surface: %d\n", status);
432+
}
426433

427434
DamageEmpty(pvfb->damage);
428435
pvfb->state->drawRequested = TRUE;
@@ -472,6 +479,30 @@ static Bool lorieCloseScreen(ScreenPtr pScreen) {
472479
return pScreen->CloseScreen(pScreen);
473480
}
474481

482+
void lorieSetWindowPixmap(WindowPtr pWindow, PixmapPtr newPixmap) {
483+
bool isRoot = pWindow == pScreenPtr->root;
484+
PixmapPtr oldPixmap = isRoot ? pScreenPtr->GetWindowPixmap(pWindow) : NULL;
485+
LoriePixmapPriv *old, *new;
486+
if (isRoot) {
487+
old = LORIE_PIXMAP_PRIV_FROM_PIXMAP(oldPixmap);
488+
new = LORIE_PIXMAP_PRIV_FROM_PIXMAP(newPixmap);
489+
if (old && old->buffer && old->locked) {
490+
LorieBuffer_unlock(old->buffer);
491+
old->locked = NULL;
492+
old->wasLocked = false;
493+
}
494+
if (new && new->buffer && !new->locked) {
495+
LorieBuffer_lock(new->buffer, &new->locked);
496+
new->wasLocked = false;
497+
}
498+
}
499+
500+
pScreenPtr->SetWindowPixmap = pvfb->SetWindowPixmap;
501+
(*pScreenPtr->SetWindowPixmap) (pWindow, newPixmap);
502+
pvfb->SetWindowPixmap = pScreenPtr->SetWindowPixmap;
503+
pScreenPtr->SetWindowPixmap = lorieSetWindowPixmap;
504+
}
505+
475506
static int lorieSetPixmapVisitWindow(WindowPtr window, void *data) {
476507
ScreenPtr screen = window->drawable.pScreen;
477508

@@ -487,6 +518,13 @@ static Bool lorieRRScreenSetSize(ScreenPtr pScreen, CARD16 width, CARD16 height,
487518
PixmapPtr oldPixmap, newPixmap;
488519
BoxRec box = { 0, 0, width, height };
489520

521+
// Drain all pending vblanks.
522+
loriePerformVblanks(true);
523+
loriePerformVblanks(false);
524+
525+
// Restore root window pixmap.
526+
present_restore_screen_pixmap(pScreenPtr);
527+
490528
SetRootClip(pScreen, ROOT_CLIP_NONE);
491529

492530
pScreen->root->drawable.width = pvfb->root.width = pScreen->width = width;
@@ -623,7 +661,9 @@ static Bool lorieScreenInit(ScreenPtr pScreen, unused int argc, unused char **ar
623661
return FALSE;
624662

625663
pvfb->CloseScreen = pScreen->CloseScreen;
664+
pvfb->SetWindowPixmap = pScreenPtr->SetWindowPixmap;
626665
pScreen->CloseScreen = lorieCloseScreen;
666+
pScreen->SetWindowPixmap = lorieSetWindowPixmap;
627667

628668
ShmRegisterFbFuncs(pScreen);
629669
miSyncShmScreenInit(pScreen);
@@ -702,20 +742,24 @@ static int loriePresentGetUstMsc(__unused RRCrtcPtr crtc, uint64_t *ust, uint64_
702742
return Success;
703743
}
704744

705-
static Bool loriePresentQueueVblank(__unused RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) {
745+
static Bool loriePresentQueueVblankInternal(__unused RRCrtcPtr crtc, uint64_t event_id, uint64_t msc, bool flip) {
706746
#pragma clang diagnostic push
707747
#pragma ide diagnostic ignored "MemoryLeak" // it is not leaked, it is destroyed in lorieRedraw
708748
struct vblank* vblank = calloc (1, sizeof (*vblank));
709749
if (!vblank)
710750
return BadAlloc;
711751

712-
*vblank = (struct vblank) { .id = event_id, .msc = msc };
752+
*vblank = (struct vblank) { .id = event_id, .msc = msc, .flip = flip };
713753
xorg_list_add(&vblank->link, &pvfb->vblank_queue);
714754

715755
return Success;
716756
#pragma clang diagnostic pop
717757
}
718758

759+
static Bool loriePresentQueueVblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) {
760+
return loriePresentQueueVblankInternal(crtc, event_id, msc, false);
761+
}
762+
719763
static void loriePresentAbortVblank(__unused RRCrtcPtr crtc, uint64_t id, __unused uint64_t msc) {
720764
struct vblank *vblank, *tmp;
721765

@@ -728,16 +772,18 @@ static void loriePresentAbortVblank(__unused RRCrtcPtr crtc, uint64_t id, __unus
728772
}
729773
}
730774

731-
static void loriePerformVblanks(void) {
775+
static void loriePerformVblanks(bool flip) {
776+
BoxRec box = { 0, 0, 1, 1 }; // lorieRedraw only checks if it is empty or not.
732777
struct vblank *vblank, *tmp;
733778
uint64_t ust, msc;
734-
pvfb->current_msc++;
735779

736780
xorg_list_for_each_entry_safe(vblank, tmp, &pvfb->vblank_queue, link) {
737-
if (vblank->msc <= pvfb->current_msc) {
781+
if (vblank->flip == flip && vblank->msc <= pvfb->current_msc) {
738782
loriePresentGetUstMsc(NULL, &ust, &msc);
739783
present_event_notify(vblank->id, ust, msc);
740784
xorg_list_del(&vblank->link);
785+
if (flip)
786+
RegionReset(DamageRegion(pvfb->damage), &box);
741787
free (vblank);
742788
}
743789
}
@@ -764,17 +810,27 @@ Bool loriePresentCheckFlip(__unused RRCrtcPtr crtc, WindowPtr window, PixmapPtr
764810
if (desc->type != LORIEBUFFER_FD && desc->type != LORIEBUFFER_AHARDWAREBUFFER)
765811
return FALSE;
766812

767-
/* currently not implemented */
768-
return FALSE;
813+
lorieRegisterBuffer(priv->buffer);
814+
present_get_window_priv(window, true);
815+
return TRUE;
816+
}
817+
818+
Bool loriePerformFlips(__unused ClientPtr clientPtr, __unused void *closure) {
819+
loriePerformVblanks(true);
820+
return TRUE;
769821
}
770822

771823
Bool loriePresentFlip(__unused RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, PixmapPtr pixmap, __unused Bool sync_flip) {
772-
/* currently not implemented */
773-
return FALSE;
824+
// Unfortunately we can not call present_event_notify inside of present_screen_info::flip
825+
// So we queue new vblank and tell Xorg to process all vblanks immediately after processing client requests
826+
loriePresentQueueVblankInternal(crtc, event_id, target_msc, true);
827+
QueueWorkProc(loriePerformFlips, NULL, NULL);
828+
lorieTriggerWorkingQueue();
829+
return true;
774830
}
775831

776832
void loriePresentUnflip(__unused ScreenPtr screen, uint64_t event_id) {
777-
/* currently not implemented */
833+
present_event_notify(event_id, 0, 0);
778834
}
779835

780836
static struct present_screen_info loriePresentInfo = {
@@ -818,7 +874,7 @@ void *lorieCreatePixmap(__unused ScreenPtr pScreen, int width, int height, __unu
818874
void lorieExaDestroyPixmap(__unused ScreenPtr pScreen, void *driverPriv) {
819875
LoriePixmapPriv *priv = driverPriv;
820876
if (priv->buffer) {
821-
if (!priv->imported)
877+
if (priv->locked)
822878
LorieBuffer_unlock(priv->buffer);
823879
LorieBuffer_release(priv->buffer);
824880
lorieUnregisterBuffer(priv->buffer);
@@ -828,7 +884,7 @@ void lorieExaDestroyPixmap(__unused ScreenPtr pScreen, void *driverPriv) {
828884

829885
Bool lorieModifyPixmapHeader(PixmapPtr pPix, __unused int w, __unused int h, __unused int depth, __unused int bitsPerbppPixel, __unused int devKind, __unused void *data) {
830886
LoriePixmapPriv *priv = exaGetPixmapDriverPrivate(pPix);
831-
if (priv)
887+
if (priv && data)
832888
priv->mem = data;
833889
return FALSE;
834890
}
@@ -838,11 +894,17 @@ Bool loriePrepareAccess(PixmapPtr pPix, int index) {
838894
if (index == EXA_PREPARE_DEST && pScreenPtr->GetScreenPixmap(pScreenPtr) == pPix)
839895
lorie_mutex_lock(&pvfb->state->lock, &pvfb->state->lockingPid);
840896

841-
if (priv->imported) {
842-
if (LorieBuffer_lock(priv->buffer, &pPix->devPrivate.ptr))
897+
if (!priv->locked && !priv->mem) {
898+
int err = LorieBuffer_lock(priv->buffer, &priv->locked);
899+
if (err) {
900+
dprintf(2, "Failed to lock buffer, err %d\n", err);
843901
return FALSE;
902+
}
903+
priv->wasLocked = FALSE;
844904
} else
845-
pPix->devPrivate.ptr = priv->locked ?: priv->mem;
905+
priv->wasLocked = TRUE;
906+
907+
pPix->devPrivate.ptr = priv->locked ?: priv->mem;
846908
return TRUE;
847909
}
848910

@@ -851,8 +913,11 @@ void lorieFinishAccess(PixmapPtr pPix, int index) {
851913
if (index == EXA_PREPARE_DEST && pScreenPtr->GetScreenPixmap(pScreenPtr) == pPix)
852914
lorie_mutex_unlock(&pvfb->state->lock, &pvfb->state->lockingPid);
853915

854-
if (priv->imported)
916+
if (!priv->wasLocked) {
855917
LorieBuffer_unlock(priv->buffer);
918+
priv->locked = NULL;
919+
priv->wasLocked = FALSE;
920+
}
856921
}
857922

858923
static ExaDriverRec lorieExa = {
@@ -886,8 +951,6 @@ static PixmapPtr loriePixmapFromFds(ScreenPtr screen, CARD8 num_fds, const int *
886951
priv = exaGetPixmapDriverPrivate(pixmap);
887952
check(!priv, "DRI3: failed to obtain pixmap private");
888953

889-
priv->imported = true;
890-
891954
if (modifier == DRM_FORMAT_MOD_INVALID || modifier == RAW_MMAPPABLE_FD) {
892955
check(!(priv->buffer = LorieBuffer_wrapFileDescriptor(width, strides[0]/4, height, AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM, fds[0], offsets[0])), "DRI3: LorieBuffer_wrapAHardwareBuffer failed.");
893956
screen->ModifyPixmapHeader(pixmap, width, height, 0, 0, strides[0], NULL);

0 commit comments

Comments
 (0)