4ef6ff96724bb50f130a241207e6756235c877a0
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 "utils/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 struct Output
23 {
24 Connector* connector;
25 Crtc* crtc;
26 Framebuffer* fbs[2];
28 int front_buf;
29 int bar_xpos;
30 };
32 static void do_flip(Output* out);
34 int main()
35 {
36 Card card;
38 if (card.master() == false)
39 printf("Not DRM master, modeset may fail\n");
41 //card.print_short();
43 vector<Output> outputs;
45 for (auto conn : card.get_connectors())
46 {
47 if (conn->connected() == false)
48 continue;
50 auto mode = conn->get_default_mode();
52 Crtc* crtc = conn->get_current_crtc();
53 if (!crtc) {
54 for (auto c : conn->get_possible_crtcs()) {
55 if (find_if(outputs.begin(), outputs.end(), [c](Output o) { return o.crtc == c; }) == outputs.end()) {
56 crtc = c;
57 break;
58 }
59 }
60 }
62 if (!crtc) {
63 printf("failed to find crtc\n");
64 return -1;
65 }
67 auto fb1 = new Framebuffer(card, mode.hdisplay, mode.vdisplay, "XR24");
68 auto fb2 = new Framebuffer(card, mode.hdisplay, mode.vdisplay, "XR24");
70 printf("conn %u, crtc %u, fb1 %u, fb2 %u\n", conn->id(), crtc->id(), fb1->id(), fb2->id());
72 Output output = { };
73 output.connector = conn;
74 output.crtc = crtc;
75 output.fbs[0] = fb1;
76 output.fbs[1] = fb2;
77 outputs.push_back(output);
78 }
80 for(auto& out : outputs) {
81 auto conn = out.connector;
82 auto crtc = out.crtc;
84 auto mode = conn->get_default_mode();
85 int r = crtc->set_mode(conn, *out.fbs[0], mode);
86 ASSERT(r == 0);
87 }
89 for(auto& out : outputs)
90 do_flip(&out);
92 main_loop(card);
94 for(auto& out : outputs) {
95 delete out.fbs[0];
96 delete out.fbs[1];
97 }
98 }
100 static void do_flip(Output* out)
101 {
102 const int bar_width = 20;
103 const int bar_speed = 8;
105 auto crtc = out->crtc;
106 auto fb = out->fbs[(out->front_buf + 1) % 2];
108 ASSERT(crtc);
109 ASSERT(fb);
111 int current_xpos = out->bar_xpos;
112 int old_xpos = (current_xpos + (fb->width() - bar_width - bar_speed)) % (fb->width() - bar_width);
113 int new_xpos = (current_xpos + bar_speed) % (fb->width() - bar_width);
115 draw_color_bar(*fb, old_xpos, new_xpos, bar_width);
117 out->bar_xpos = new_xpos;
119 auto& card = crtc->card();
121 if (card.has_atomic()) {
122 int r;
124 AtomicReq ctx(card);
126 ctx.add(crtc, card.get_prop("FB_ID"), fb->id());
128 r = ctx.test();
129 ASSERT(r == 0);
131 r = ctx.commit(out);
132 ASSERT(r == 0);
133 } else {
134 int r = drmModePageFlip(card.fd(), crtc->id(), fb->id(), DRM_MODE_PAGE_FLIP_EVENT, out);
135 ASSERT(r == 0);
136 }
137 }
139 static void page_flip_handler(int fd, unsigned int frame,
140 unsigned int sec, unsigned int usec,
141 void *data)
142 {
143 //printf("flip event %d, %d, %u, %u, %p\n", fd, frame, sec, usec, data);
145 auto out = (Output*)data;
147 out->front_buf = (out->front_buf + 1) % 2;
149 do_flip(out);
150 }
153 static void main_loop(Card& card)
154 {
155 drmEventContext ev = {
156 .version = DRM_EVENT_CONTEXT_VERSION,
157 .vblank_handler = 0,
158 .page_flip_handler = page_flip_handler,
159 };
161 fd_set fds;
163 FD_ZERO(&fds);
165 int fd = card.fd();
167 printf("press enter to exit\n");
169 while (true) {
170 int r;
172 FD_SET(0, &fds);
173 FD_SET(fd, &fds);
175 r = select(fd + 1, &fds, NULL, NULL, NULL);
176 if (r < 0) {
177 fprintf(stderr, "select() failed with %d: %m\n", errno);
178 break;
179 } else if (FD_ISSET(0, &fds)) {
180 fprintf(stderr, "exit due to user-input\n");
181 break;
182 } else if (FD_ISSET(fd, &fds)) {
183 drmHandleEvent(fd, &ev);
184 }
185 }
186 }
189 static const RGB colors32[] = {
190 RGB(255, 255, 255),
191 RGB(255, 0, 0),
192 RGB(255, 255, 255),
193 RGB(0, 255, 0),
194 RGB(255, 255, 255),
195 RGB(0, 0, 255),
196 RGB(255, 255, 255),
197 RGB(200, 200, 200),
198 RGB(255, 255, 255),
199 RGB(100, 100, 100),
200 RGB(255, 255, 255),
201 RGB(50, 50, 50),
202 };
204 static const uint16_t colors16[] = {
205 colors32[0].rgb565(),
206 colors32[1].rgb565(),
207 colors32[2].rgb565(),
208 colors32[3].rgb565(),
209 colors32[4].rgb565(),
210 colors32[5].rgb565(),
211 colors32[6].rgb565(),
212 colors32[7].rgb565(),
213 colors32[8].rgb565(),
214 colors32[9].rgb565(),
215 colors32[10].rgb565(),
216 colors32[11].rgb565(),
217 };
219 static void drm_draw_color_bar_rgb888(Framebuffer& buf, int old_xpos, int xpos, int width)
220 {
221 for (unsigned y = 0; y < buf.height(); ++y) {
222 RGB bcol = colors32[y * ARRAY_SIZE(colors32) / buf.height()];
223 uint32_t *line = (uint32_t*)(buf.map(0) + buf.stride(0) * y);
225 if (old_xpos >= 0) {
226 for (int x = old_xpos; x < old_xpos + width; ++x)
227 line[x] = 0;
228 }
230 for (int x = xpos; x < xpos + width; ++x)
231 line[x] = bcol.raw;
232 }
233 }
235 static void drm_draw_color_bar_rgb565(Framebuffer& buf, int old_xpos, int xpos, int width)
236 {
237 static_assert(ARRAY_SIZE(colors32) == ARRAY_SIZE(colors16), "bad colors arrays");
239 for (unsigned y = 0; y < buf.height(); ++y) {
240 uint16_t bcol = colors16[y * ARRAY_SIZE(colors16) / buf.height()];
241 uint16_t *line = (uint16_t*)(buf.map(0) + buf.stride(0) * y);
243 if (old_xpos >= 0) {
244 for (int x = old_xpos; x < old_xpos + width; ++x)
245 line[x] = 0;
246 }
248 for (int x = xpos; x < xpos + width; ++x)
249 line[x] = bcol;
250 }
251 }
253 static void drm_draw_color_bar_semiplanar_yuv(Framebuffer& buf, int old_xpos, int xpos, int width)
254 {
255 const uint8_t colors[] = {
256 0xff,
257 0x00,
258 0xff,
259 0x20,
260 0xff,
261 0x40,
262 0xff,
263 0x80,
264 0xff,
265 };
267 for (unsigned y = 0; y < buf.height(); ++y) {
268 unsigned int bcol = colors[y * ARRAY_SIZE(colors) / buf.height()];
269 uint8_t *line = (uint8_t*)(buf.map(0) + buf.stride(0) * y);
271 if (old_xpos >= 0) {
272 for (int x = old_xpos; x < old_xpos + width; ++x)
273 line[x] = 0;
274 }
276 for (int x = xpos; x < xpos + width; ++x)
277 line[x] = bcol;
278 }
279 }
281 static void draw_color_bar(Framebuffer& buf, int old_xpos, int xpos, int width)
282 {
283 switch (buf.format()) {
284 case DRM_FORMAT_NV12:
285 case DRM_FORMAT_NV21:
286 // XXX not right but gets something on the screen
287 drm_draw_color_bar_semiplanar_yuv(buf, old_xpos, xpos, width);
288 break;
290 case DRM_FORMAT_YUYV:
291 case DRM_FORMAT_UYVY:
292 // XXX not right but gets something on the screen
293 drm_draw_color_bar_rgb565(buf, old_xpos, xpos, width);
294 break;
296 case DRM_FORMAT_RGB565:
297 drm_draw_color_bar_rgb565(buf, old_xpos, xpos, width);
298 break;
300 case DRM_FORMAT_XRGB8888:
301 drm_draw_color_bar_rgb888(buf, old_xpos, xpos, width);
302 break;
304 default:
305 ASSERT(false);
306 }
307 }