Update README.md
[android/external-libkmsxx.git] / utils / db.cpp
1 #include <cstdio>
2 #include <algorithm>
3 #include <chrono>
5 #include <xf86drm.h>
6 #include <xf86drmMode.h>
7 #include <drm_fourcc.h>
9 #include <kms++.h>
10 #include <kms++util.h>
12 using namespace std;
13 using namespace kms;
15 static void main_loop(Card& card);
17 class Flipper
18 {
19 public:
20         Flipper(Card& card, unsigned width, unsigned height)
21                 : m_current(0), m_bar_xpos(0)
22         {
23                 auto format = PixelFormat::XRGB8888;
24                 m_fbs[0] = new DumbFramebuffer(card, width, height, format);
25                 m_fbs[1] = new DumbFramebuffer(card, width, height, format);
26         }
28         ~Flipper()
29         {
30                 delete m_fbs[0];
31                 delete m_fbs[1];
32         }
34         Framebuffer* get_next()
35         {
36                 m_current ^= 1;
38                 const int bar_width = 20;
39                 const int bar_speed = 8;
41                 auto fb = m_fbs[m_current];
43                 int current_xpos = m_bar_xpos;
44                 int old_xpos = (current_xpos + (fb->width() - bar_width - bar_speed)) % (fb->width() - bar_width);
45                 int new_xpos = (current_xpos + bar_speed) % (fb->width() - bar_width);
47                 draw_color_bar(*fb, old_xpos, new_xpos, bar_width);
49                 m_bar_xpos = new_xpos;
51                 return fb;
52         }
54 private:
55         DumbFramebuffer* m_fbs[2];
57         int m_current;
58         int m_bar_xpos;
59 };
61 class OutputFlipHandler : private PageFlipHandlerBase
62 {
63 public:
64         OutputFlipHandler(Connector* conn, Crtc* crtc, const Videomode& mode)
65                 : m_connector(conn), m_crtc(crtc), m_mode(mode),
66                   m_flipper(conn->card(), mode.hdisplay, mode.vdisplay),
67                   m_plane(0), m_plane_flipper(0)
68         {
69         }
71         OutputFlipHandler(Connector* conn, Crtc* crtc, const Videomode& mode,
72                           Plane* plane, unsigned pwidth, unsigned pheight)
73                 : m_connector(conn), m_crtc(crtc), m_mode(mode),
74                   m_flipper(conn->card(), mode.hdisplay, mode.vdisplay),
75                   m_plane(plane)
76         {
77                 m_plane_flipper = new Flipper(conn->card(), pwidth, pheight);
78         }
80         ~OutputFlipHandler()
81         {
82                 if (m_plane_flipper)
83                         delete m_plane_flipper;
84         }
86         OutputFlipHandler(const OutputFlipHandler& other) = delete;
87         OutputFlipHandler& operator=(const OutputFlipHandler& other) = delete;
89         void set_mode()
90         {
91                 auto fb = m_flipper.get_next();
92                 int r = m_crtc->set_mode(m_connector, *fb, m_mode);
93                 ASSERT(r == 0);
95                 if (m_crtc->card().has_atomic())
96                         m_root_plane = m_crtc->get_primary_plane();
98                 if (m_plane) {
99                         auto planefb = m_plane_flipper->get_next();
100                         r = m_crtc->set_plane(m_plane, *planefb,
101                                               0, 0, planefb->width(), planefb->height(),
102                                               0, 0, planefb->width(), planefb->height());
103                         ASSERT(r == 0);
104                 }
105         }
107         void start_flipping()
108         {
109                 m_time_last = m_t1 = std::chrono::steady_clock::now();
110                 m_slowest_frame = std::chrono::duration<float>::min();
111                 m_frame_num = 0;
112                 queue_next();
113         }
115 private:
116         void handle_page_flip(uint32_t frame, double time)
117         {
118                 ++m_frame_num;
120                 auto now = std::chrono::steady_clock::now();
122                 std::chrono::duration<float> diff = now - m_time_last;
123                 if (diff > m_slowest_frame)
124                         m_slowest_frame = diff;
126                 if (m_frame_num  % 100 == 0) {
127                         std::chrono::duration<float> fsec = now - m_t1;
128                         printf("Output %d: fps %f, slowest %.2f ms\n",
129                                m_connector->idx(), 100.0 / fsec.count(),
130                                m_slowest_frame.count() * 1000);
131                         m_t1 = now;
132                         m_slowest_frame = std::chrono::duration<float>::min();
133                 }
135                 m_time_last = now;
137                 queue_next();
138         }
140         void queue_next()
141         {
142                 auto crtc = m_crtc;
143                 auto& card = crtc->card();
145                 auto fb = m_flipper.get_next();
146                 Framebuffer* planefb = m_plane ? m_plane_flipper->get_next() : 0;
148                 if (card.has_atomic()) {
149                         int r;
151                         AtomicReq req(card);
153                         req.add(m_root_plane, "FB_ID", fb->id());
154                         if (m_plane)
155                                 req.add(m_plane, "FB_ID", planefb->id());
157                         r = req.test();
158                         ASSERT(r == 0);
160                         r = req.commit(this);
161                         ASSERT(r == 0);
162                 } else {
163                         int r = crtc->page_flip(*fb, this);
164                         ASSERT(r == 0);
166                         if (m_plane) {
167                                 r = m_crtc->set_plane(m_plane, *planefb,
168                                                       0, 0, planefb->width(), planefb->height(),
169                                                       0, 0, planefb->width(), planefb->height());
170                                 ASSERT(r == 0);
171                         }
172                 }
173         }
175 private:
176         Connector* m_connector;
177         Crtc* m_crtc;
178         Videomode m_mode;
179         Plane* m_root_plane;
181         int m_frame_num;
182         chrono::steady_clock::time_point m_t1;
183         chrono::steady_clock::time_point m_time_last;
184         chrono::duration<float> m_slowest_frame;
186         Flipper m_flipper;
188         Plane* m_plane;
189         Flipper* m_plane_flipper;
190 };
192 int main()
194         Card card;
196         if (card.master() == false)
197                 printf("Not DRM master, modeset may fail\n");
199         vector<OutputFlipHandler*> outputs;
201         for (auto pipe : card.get_connected_pipelines())
202         {
203                 auto conn = pipe.connector;
204                 auto crtc = pipe.crtc;
205                 auto mode = conn->get_default_mode();
208                 Plane* plane = 0;
209 #if 0 // disable the plane for now
210                 for (Plane* p : crtc->get_possible_planes()) {
211                         if (p->plane_type() == PlaneType::Overlay) {
212                                 plane = p;
213                                 break;
214                         }
215                 }
216 #endif
217                 OutputFlipHandler* output;
218                 if (plane)
219                         output = new OutputFlipHandler(conn, crtc, mode, plane, 500, 400);
220                 else
221                         output = new OutputFlipHandler(conn, crtc, mode);
222                 outputs.push_back(output);
223         }
225         for(auto out : outputs)
226                 out->set_mode();
228         for(auto out : outputs)
229                 out->start_flipping();
231         main_loop(card);
233         for(auto out : outputs)
234                 delete out;
237 static void main_loop(Card& card)
239         fd_set fds;
241         FD_ZERO(&fds);
243         int fd = card.fd();
245         printf("press enter to exit\n");
247         while (true) {
248                 int r;
250                 FD_SET(0, &fds);
251                 FD_SET(fd, &fds);
253                 r = select(fd + 1, &fds, NULL, NULL, NULL);
254                 if (r < 0) {
255                         fprintf(stderr, "select() failed with %d: %m\n", errno);
256                         break;
257                 } else if (FD_ISSET(0, &fds)) {
258                         fprintf(stderr, "exit due to user-input\n");
259                         break;
260                 } else if (FD_ISSET(fd, &fds)) {
261                         card.call_page_flip_handlers();
262                 }
263         }