1 #include <cstdio>
2 #include <algorithm>
4 #include <xf86drm.h>
5 #include <xf86drmMode.h>
6 #include <drm_fourcc.h>
8 #include "kms++.h"
9 #include "color.h"
11 #include "test.h"
13 using namespace std;
14 using namespace kms;
16 static void draw_color_bar(Framebuffer& buf, int old_xpos, int xpos, int width);
18 static void main_loop(Card& card);
20 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
22 class OutputFlipHandler
23 {
24 public:
25 OutputFlipHandler(Connector* conn, Crtc* crtc, Framebuffer* fb1, Framebuffer* fb2)
26 : m_connector(conn), m_crtc(crtc), m_fbs { fb1, fb2 }, m_front_buf(1), m_bar_xpos(0)
27 {
28 }
30 ~OutputFlipHandler()
31 {
32 delete m_fbs[0];
33 delete m_fbs[1];
34 }
36 OutputFlipHandler(const OutputFlipHandler& other) = delete;
37 OutputFlipHandler& operator=(const OutputFlipHandler& other) = delete;
39 void set_mode()
40 {
41 auto mode = m_connector->get_default_mode();
42 int r = m_crtc->set_mode(m_connector, *m_fbs[0], mode);
43 ASSERT(r == 0);
44 }
46 void handle_event()
47 {
48 m_front_buf = (m_front_buf + 1) % 2;
50 const int bar_width = 20;
51 const int bar_speed = 8;
53 auto crtc = m_crtc;
54 auto fb = m_fbs[(m_front_buf + 1) % 2];
56 ASSERT(crtc);
57 ASSERT(fb);
59 int current_xpos = m_bar_xpos;
60 int old_xpos = (current_xpos + (fb->width() - bar_width - bar_speed)) % (fb->width() - bar_width);
61 int new_xpos = (current_xpos + bar_speed) % (fb->width() - bar_width);
63 draw_color_bar(*fb, old_xpos, new_xpos, bar_width);
65 m_bar_xpos = new_xpos;
67 auto& card = crtc->card();
69 if (card.has_atomic()) {
70 int r;
72 AtomicReq ctx(card);
74 ctx.add(m_crtc, card.get_prop("FB_ID"), fb->id());
76 r = ctx.test();
77 ASSERT(r == 0);
79 r = ctx.commit(this);
80 ASSERT(r == 0);
81 } else {
82 int r = crtc->page_flip(*fb, this);
83 ASSERT(r == 0);
84 }
85 }
87 private:
88 Connector* m_connector;
89 Crtc* m_crtc;
90 Framebuffer* m_fbs[2];
92 int m_front_buf;
93 int m_bar_xpos;
94 };
96 int main()
97 {
98 Card card;
100 if (card.master() == false)
101 printf("Not DRM master, modeset may fail\n");
103 //card.print_short();
105 vector<OutputFlipHandler*> outputs;
107 for (auto pipe : card.get_connected_pipelines())
108 {
109 auto conn = pipe.connector;
110 auto crtc = pipe.crtc;
112 auto mode = conn->get_default_mode();
114 auto fb1 = new Framebuffer(card, mode.hdisplay, mode.vdisplay, "XR24");
115 auto fb2 = new Framebuffer(card, mode.hdisplay, mode.vdisplay, "XR24");
117 printf("conn %u, crtc %u, fb1 %u, fb2 %u\n", conn->id(), crtc->id(), fb1->id(), fb2->id());
119 auto output = new OutputFlipHandler(conn, crtc, fb1, fb2);
120 outputs.push_back(output);
121 }
123 for(auto out : outputs)
124 out->set_mode();
126 for(auto out : outputs)
127 out->handle_event();
129 main_loop(card);
131 for(auto out : outputs)
132 delete out;
133 }
135 static void page_flip_handler(int fd, unsigned int frame,
136 unsigned int sec, unsigned int usec,
137 void *data)
138 {
139 //printf("flip event %d, %d, %u, %u, %p\n", fd, frame, sec, usec, data);
141 auto out = (OutputFlipHandler*)data;
143 out->handle_event();
144 }
147 static void main_loop(Card& card)
148 {
149 drmEventContext ev = {
150 .version = DRM_EVENT_CONTEXT_VERSION,
151 .vblank_handler = 0,
152 .page_flip_handler = page_flip_handler,
153 };
155 fd_set fds;
157 FD_ZERO(&fds);
159 int fd = card.fd();
161 printf("press enter to exit\n");
163 while (true) {
164 int r;
166 FD_SET(0, &fds);
167 FD_SET(fd, &fds);
169 r = select(fd + 1, &fds, NULL, NULL, NULL);
170 if (r < 0) {
171 fprintf(stderr, "select() failed with %d: %m\n", errno);
172 break;
173 } else if (FD_ISSET(0, &fds)) {
174 fprintf(stderr, "exit due to user-input\n");
175 break;
176 } else if (FD_ISSET(fd, &fds)) {
177 drmHandleEvent(fd, &ev);
178 }
179 }
180 }
183 static const RGB colors32[] = {
184 RGB(255, 255, 255),
185 RGB(255, 0, 0),
186 RGB(255, 255, 255),
187 RGB(0, 255, 0),
188 RGB(255, 255, 255),
189 RGB(0, 0, 255),
190 RGB(255, 255, 255),
191 RGB(200, 200, 200),
192 RGB(255, 255, 255),
193 RGB(100, 100, 100),
194 RGB(255, 255, 255),
195 RGB(50, 50, 50),
196 };
198 static const uint16_t colors16[] = {
199 colors32[0].rgb565(),
200 colors32[1].rgb565(),
201 colors32[2].rgb565(),
202 colors32[3].rgb565(),
203 colors32[4].rgb565(),
204 colors32[5].rgb565(),
205 colors32[6].rgb565(),
206 colors32[7].rgb565(),
207 colors32[8].rgb565(),
208 colors32[9].rgb565(),
209 colors32[10].rgb565(),
210 colors32[11].rgb565(),
211 };
213 static void drm_draw_color_bar_rgb888(Framebuffer& buf, int old_xpos, int xpos, int width)
214 {
215 for (unsigned y = 0; y < buf.height(); ++y) {
216 RGB bcol = colors32[y * ARRAY_SIZE(colors32) / buf.height()];
217 uint32_t *line = (uint32_t*)(buf.map(0) + buf.stride(0) * y);
219 if (old_xpos >= 0) {
220 for (int x = old_xpos; x < old_xpos + width; ++x)
221 line[x] = 0;
222 }
224 for (int x = xpos; x < xpos + width; ++x)
225 line[x] = bcol.raw;
226 }
227 }
229 static void drm_draw_color_bar_rgb565(Framebuffer& buf, int old_xpos, int xpos, int width)
230 {
231 static_assert(ARRAY_SIZE(colors32) == ARRAY_SIZE(colors16), "bad colors arrays");
233 for (unsigned y = 0; y < buf.height(); ++y) {
234 uint16_t bcol = colors16[y * ARRAY_SIZE(colors16) / buf.height()];
235 uint16_t *line = (uint16_t*)(buf.map(0) + buf.stride(0) * y);
237 if (old_xpos >= 0) {
238 for (int x = old_xpos; x < old_xpos + width; ++x)
239 line[x] = 0;
240 }
242 for (int x = xpos; x < xpos + width; ++x)
243 line[x] = bcol;
244 }
245 }
247 static void drm_draw_color_bar_semiplanar_yuv(Framebuffer& buf, int old_xpos, int xpos, int width)
248 {
249 const uint8_t colors[] = {
250 0xff,
251 0x00,
252 0xff,
253 0x20,
254 0xff,
255 0x40,
256 0xff,
257 0x80,
258 0xff,
259 };
261 for (unsigned y = 0; y < buf.height(); ++y) {
262 unsigned int bcol = colors[y * ARRAY_SIZE(colors) / buf.height()];
263 uint8_t *line = (uint8_t*)(buf.map(0) + buf.stride(0) * y);
265 if (old_xpos >= 0) {
266 for (int x = old_xpos; x < old_xpos + width; ++x)
267 line[x] = 0;
268 }
270 for (int x = xpos; x < xpos + width; ++x)
271 line[x] = bcol;
272 }
273 }
275 static void draw_color_bar(Framebuffer& buf, int old_xpos, int xpos, int width)
276 {
277 switch (buf.format()) {
278 case DRM_FORMAT_NV12:
279 case DRM_FORMAT_NV21:
280 // XXX not right but gets something on the screen
281 drm_draw_color_bar_semiplanar_yuv(buf, old_xpos, xpos, width);
282 break;
284 case DRM_FORMAT_YUYV:
285 case DRM_FORMAT_UYVY:
286 // XXX not right but gets something on the screen
287 drm_draw_color_bar_rgb565(buf, old_xpos, xpos, width);
288 break;
290 case DRM_FORMAT_RGB565:
291 drm_draw_color_bar_rgb565(buf, old_xpos, xpos, width);
292 break;
294 case DRM_FORMAT_XRGB8888:
295 drm_draw_color_bar_rgb888(buf, old_xpos, xpos, width);
296 break;
298 default:
299 ASSERT(false);
300 }
301 }