hc
2023-02-13 e440ec23c5a540cdd3f7464e8779219be6fd3d95
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
From 22f5665de79513c41fbef8f1b918f44d184daf1f Mon Sep 17 00:00:00 2001
From: Jeffy Chen <jeffy.chen@rock-chips.com>
Date: Tue, 16 Apr 2019 18:46:49 +0800
Subject: [PATCH 17/31] linuxfb: Use triple buffer by default
 
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
---
 .../platforms/linuxfb/qlinuxfbdrmscreen.cpp   | 56 +++++++++++++++----
 1 file changed, 44 insertions(+), 12 deletions(-)
 
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp
index dcc1ef27..29d146f4 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp
@@ -59,7 +59,13 @@ QT_BEGIN_NAMESPACE
 
 Q_LOGGING_CATEGORY(qLcFbDrm, "qt.qpa.fb")
 
+#define TRIPLE_BUFFER
+
+#ifdef TRIPLE_BUFFER
+static const int BUFFER_COUNT = 3;
+#else
 static const int BUFFER_COUNT = 2;
+#endif
 
 class QLinuxFbDevice : public QKmsDevice
 {
@@ -75,12 +81,12 @@ public:
     };
 
     struct Output {
-        Output() : backFb(0), flipped(false) { }
+        Output() : backFb(0), flipPending(false) { }
         QKmsOutput kmsOutput;
         Framebuffer fb[BUFFER_COUNT];
         QRegion dirty[BUFFER_COUNT];
         int backFb;
-        bool flipped;
+        bool flipPending;
         QSize currentRes() const {
             const drmModeModeInfo &modeInfo(kmsOutput.modes[kmsOutput.mode]);
             return QSize(modeInfo.hdisplay, modeInfo.vdisplay);
@@ -97,6 +103,7 @@ public:
     void setMode();
 
     void swapBuffers(Output *output);
+    void waitForFlip(Output *output);
 
     int outputCount() const { return m_outputs.count(); }
     Output *output(int idx) { return &m_outputs[idx]; }
@@ -301,7 +308,7 @@ void QLinuxFbDevice::createFramebuffers()
                 return;
         }
         output.backFb = 0;
-        output.flipped = false;
+        output.flipPending = false;
     }
 }
 
@@ -355,19 +362,18 @@ void QLinuxFbDevice::pageFlipHandler(int fd, unsigned int sequence,
     Q_UNUSED(tv_usec);
 
     Output *output = static_cast<Output *>(user_data);
+
+#ifndef TRIPLE_BUFFER
+    // The next buffer would be available after flipped
     output->backFb = (output->backFb + 1) % BUFFER_COUNT;
+#endif
+
+    output->flipPending = false;
 }
 
-void QLinuxFbDevice::swapBuffers(Output *output)
+void QLinuxFbDevice::waitForFlip(Output *output)
 {
-    Framebuffer &fb(output->fb[output->backFb]);
-    if (drmModePageFlip(fd(), output->kmsOutput.crtc_id, fb.fb, DRM_MODE_PAGE_FLIP_EVENT, output) == -1) {
-        qErrnoWarning(errno, "Page flip failed");
-        return;
-    }
-
-    const int fbIdx = output->backFb;
-    while (output->backFb == fbIdx) {
+    while (output->flipPending) {
         drmEventContext drmEvent;
         memset(&drmEvent, 0, sizeof(drmEvent));
         drmEvent.version = 2;
@@ -379,6 +385,27 @@ void QLinuxFbDevice::swapBuffers(Output *output)
     }
 }
 
+void QLinuxFbDevice::swapBuffers(Output *output)
+{
+#ifdef TRIPLE_BUFFER
+    // Wait flip to make sure last buffer displayed
+    waitForFlip(output);
+#endif
+
+    Framebuffer &fb(output->fb[output->backFb]);
+    if (drmModePageFlip(fd(), output->kmsOutput.crtc_id, fb.fb, DRM_MODE_PAGE_FLIP_EVENT, output) == -1) {
+        qErrnoWarning(errno, "Page flip failed");
+        return;
+    }
+
+    output->flipPending = true;
+
+#ifdef TRIPLE_BUFFER
+    // The next buffer should always available in triple buffer case.
+    output->backFb = (output->backFb + 1) % BUFFER_COUNT;
+#endif
+}
+
 QLinuxFbDrmScreen::QLinuxFbDrmScreen(const QStringList &args)
     : m_screenConfig(nullptr),
       m_device(nullptr)
@@ -436,6 +463,11 @@ QRegion QLinuxFbDrmScreen::doRedraw()
     for (int i = 0; i < BUFFER_COUNT; ++i)
         output->dirty[i] += dirty;
 
+#ifndef TRIPLE_BUFFER
+    // Wait flip before accessing new buffer
+    m_device->waitForFlip(output);
+#endif
+
     if (output->fb[output->backFb].wrapper.isNull())
         return dirty;
 
-- 
2.20.1