47ed273137b5ca3bbfca0dfc61a42f20805620ee
1 #include <cstdio>
2 #include <algorithm>
4 #include <xf86drm.h>
5 #include <xf86drmMode.h>
6 #include <drm_fourcc.h>
8 #include "kms++.h"
10 #include "test.h"
12 using namespace std;
13 using namespace kms;
15 static void draw_color_bar(DumbFramebuffer& buf, int old_xpos, int xpos, int width);
17 static void main_loop(Card& card);
19 class OutputFlipHandler
20 {
21 public:
22 OutputFlipHandler(Connector* conn, Crtc* crtc, DumbFramebuffer* fb1, DumbFramebuffer* fb2)
23 : m_connector(conn), m_crtc(crtc), m_fbs { fb1, fb2 }, m_front_buf(1), m_bar_xpos(0)
24 {
25 }
27 ~OutputFlipHandler()
28 {
29 delete m_fbs[0];
30 delete m_fbs[1];
31 }
33 OutputFlipHandler(const OutputFlipHandler& other) = delete;
34 OutputFlipHandler& operator=(const OutputFlipHandler& other) = delete;
36 void set_mode()
37 {
38 auto mode = m_connector->get_default_mode();
39 int r = m_crtc->set_mode(m_connector, *m_fbs[0], mode);
40 ASSERT(r == 0);
41 }
43 void handle_event()
44 {
45 m_front_buf = (m_front_buf + 1) % 2;
47 const int bar_width = 20;
48 const int bar_speed = 8;
50 auto crtc = m_crtc;
51 auto fb = m_fbs[(m_front_buf + 1) % 2];
53 ASSERT(crtc);
54 ASSERT(fb);
56 int current_xpos = m_bar_xpos;
57 int old_xpos = (current_xpos + (fb->width() - bar_width - bar_speed)) % (fb->width() - bar_width);
58 int new_xpos = (current_xpos + bar_speed) % (fb->width() - bar_width);
60 draw_color_bar(*fb, old_xpos, new_xpos, bar_width);
62 m_bar_xpos = new_xpos;
64 auto& card = crtc->card();
66 if (card.has_atomic()) {
67 int r;
69 AtomicReq ctx(card);
71 ctx.add(m_crtc, card.get_prop("FB_ID"), fb->id());
73 r = ctx.test();
74 ASSERT(r == 0);
76 r = ctx.commit(this);
77 ASSERT(r == 0);
78 } else {
79 int r = crtc->page_flip(*fb, this);
80 ASSERT(r == 0);
81 }
82 }
84 private:
85 Connector* m_connector;
86 Crtc* m_crtc;
87 DumbFramebuffer* m_fbs[2];
89 int m_front_buf;
90 int m_bar_xpos;
91 };
93 int main()
94 {
95 Card card;
97 if (card.master() == false)
98 printf("Not DRM master, modeset may fail\n");
100 //card.print_short();
102 vector<OutputFlipHandler*> outputs;
104 for (auto pipe : card.get_connected_pipelines())
105 {
106 auto conn = pipe.connector;
107 auto crtc = pipe.crtc;
109 auto mode = conn->get_default_mode();
111 auto fb1 = new DumbFramebuffer(card, mode.hdisplay, mode.vdisplay, "XR24");
112 auto fb2 = new DumbFramebuffer(card, mode.hdisplay, mode.vdisplay, "XR24");
114 printf("conn %u, crtc %u, fb1 %u, fb2 %u\n", conn->id(), crtc->id(), fb1->id(), fb2->id());
116 auto output = new OutputFlipHandler(conn, crtc, fb1, fb2);
117 outputs.push_back(output);
118 }
120 for(auto out : outputs)
121 out->set_mode();
123 for(auto out : outputs)
124 out->handle_event();
126 main_loop(card);
128 for(auto out : outputs)
129 delete out;
130 }
132 static void page_flip_handler(int fd, unsigned int frame,
133 unsigned int sec, unsigned int usec,
134 void *data)
135 {
136 //printf("flip event %d, %d, %u, %u, %p\n", fd, frame, sec, usec, data);
138 auto out = (OutputFlipHandler*)data;
140 out->handle_event();
141 }
144 static void main_loop(Card& card)
145 {
146 drmEventContext ev = {
147 .version = DRM_EVENT_CONTEXT_VERSION,
148 .vblank_handler = 0,
149 .page_flip_handler = page_flip_handler,
150 };
152 fd_set fds;
154 FD_ZERO(&fds);
156 int fd = card.fd();
158 printf("press enter to exit\n");
160 while (true) {
161 int r;
163 FD_SET(0, &fds);
164 FD_SET(fd, &fds);
166 r = select(fd + 1, &fds, NULL, NULL, NULL);
167 if (r < 0) {
168 fprintf(stderr, "select() failed with %d: %m\n", errno);
169 break;
170 } else if (FD_ISSET(0, &fds)) {
171 fprintf(stderr, "exit due to user-input\n");
172 break;
173 } else if (FD_ISSET(fd, &fds)) {
174 drmHandleEvent(fd, &ev);
175 }
176 }
177 }
180 static const RGB colors32[] = {
181 RGB(255, 255, 255),
182 RGB(255, 0, 0),
183 RGB(255, 255, 255),
184 RGB(0, 255, 0),
185 RGB(255, 255, 255),
186 RGB(0, 0, 255),
187 RGB(255, 255, 255),
188 RGB(200, 200, 200),
189 RGB(255, 255, 255),
190 RGB(100, 100, 100),
191 RGB(255, 255, 255),
192 RGB(50, 50, 50),
193 };
195 static const uint16_t colors16[] = {
196 colors32[0].rgb565(),
197 colors32[1].rgb565(),
198 colors32[2].rgb565(),
199 colors32[3].rgb565(),
200 colors32[4].rgb565(),
201 colors32[5].rgb565(),
202 colors32[6].rgb565(),
203 colors32[7].rgb565(),
204 colors32[8].rgb565(),
205 colors32[9].rgb565(),
206 colors32[10].rgb565(),
207 colors32[11].rgb565(),
208 };
210 static void drm_draw_color_bar_rgb888(DumbFramebuffer& buf, int old_xpos, int xpos, int width)
211 {
212 for (unsigned y = 0; y < buf.height(); ++y) {
213 RGB bcol = colors32[y * ARRAY_SIZE(colors32) / buf.height()];
214 uint32_t *line = (uint32_t*)(buf.map(0) + buf.stride(0) * y);
216 if (old_xpos >= 0) {
217 for (int x = old_xpos; x < old_xpos + width; ++x)
218 line[x] = 0;
219 }
221 for (int x = xpos; x < xpos + width; ++x)
222 line[x] = bcol.raw;
223 }
224 }
226 static void drm_draw_color_bar_rgb565(DumbFramebuffer& buf, int old_xpos, int xpos, int width)
227 {
228 static_assert(ARRAY_SIZE(colors32) == ARRAY_SIZE(colors16), "bad colors arrays");
230 for (unsigned y = 0; y < buf.height(); ++y) {
231 uint16_t bcol = colors16[y * ARRAY_SIZE(colors16) / buf.height()];
232 uint16_t *line = (uint16_t*)(buf.map(0) + buf.stride(0) * y);
234 if (old_xpos >= 0) {
235 for (int x = old_xpos; x < old_xpos + width; ++x)
236 line[x] = 0;
237 }
239 for (int x = xpos; x < xpos + width; ++x)
240 line[x] = bcol;
241 }
242 }
244 static void drm_draw_color_bar_semiplanar_yuv(DumbFramebuffer& buf, int old_xpos, int xpos, int width)
245 {
246 const uint8_t colors[] = {
247 0xff,
248 0x00,
249 0xff,
250 0x20,
251 0xff,
252 0x40,
253 0xff,
254 0x80,
255 0xff,
256 };
258 for (unsigned y = 0; y < buf.height(); ++y) {
259 unsigned int bcol = colors[y * ARRAY_SIZE(colors) / buf.height()];
260 uint8_t *line = (uint8_t*)(buf.map(0) + buf.stride(0) * y);
262 if (old_xpos >= 0) {
263 for (int x = old_xpos; x < old_xpos + width; ++x)
264 line[x] = 0;
265 }
267 for (int x = xpos; x < xpos + width; ++x)
268 line[x] = bcol;
269 }
270 }
272 static void draw_color_bar(DumbFramebuffer& buf, int old_xpos, int xpos, int width)
273 {
274 switch (buf.format()) {
275 case DRM_FORMAT_NV12:
276 case DRM_FORMAT_NV21:
277 // XXX not right but gets something on the screen
278 drm_draw_color_bar_semiplanar_yuv(buf, old_xpos, xpos, width);
279 break;
281 case DRM_FORMAT_YUYV:
282 case DRM_FORMAT_UYVY:
283 // XXX not right but gets something on the screen
284 drm_draw_color_bar_rgb565(buf, old_xpos, xpos, width);
285 break;
287 case DRM_FORMAT_RGB565:
288 drm_draw_color_bar_rgb565(buf, old_xpos, xpos, width);
289 break;
291 case DRM_FORMAT_XRGB8888:
292 drm_draw_color_bar_rgb888(buf, old_xpos, xpos, width);
293 break;
295 default:
296 ASSERT(false);
297 }
298 }