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 // XXX
127 //ctx.add(plane, card.get_prop("CRTC_X"), 50);
128 //ctx.add(plane, card.get_prop("CRTC_Y"), 50);
130 r = ctx.test();
131 ASSERT(r == 0);
133 r = ctx.commit();
134 ASSERT(r == 0);
135 } else {
136 int r = drmModePageFlip(card.fd(), crtc->id(), fb->id(), DRM_MODE_PAGE_FLIP_EVENT, out);
137 ASSERT(r == 0);
138 }
139 }
141 static void page_flip_handler(int fd, unsigned int frame,
142 unsigned int sec, unsigned int usec,
143 void *data)
144 {
145 //printf("flip event %d, %d, %u, %u, %p\n", fd, frame, sec, usec, data);
147 auto out = (Output*)data;
149 out->front_buf = (out->front_buf + 1) % 2;
151 do_flip(out);
152 }
155 static void main_loop(Card& card)
156 {
157 drmEventContext ev = {
158 .version = DRM_EVENT_CONTEXT_VERSION,
159 .vblank_handler = 0,
160 .page_flip_handler = page_flip_handler,
161 };
163 fd_set fds;
165 FD_ZERO(&fds);
167 int fd = card.fd();
169 printf("press enter to exit\n");
171 while (true) {
172 int r;
174 FD_SET(0, &fds);
175 FD_SET(fd, &fds);
177 r = select(fd + 1, &fds, NULL, NULL, NULL);
178 if (r < 0) {
179 fprintf(stderr, "select() failed with %d: %m\n", errno);
180 break;
181 } else if (FD_ISSET(0, &fds)) {
182 fprintf(stderr, "exit due to user-input\n");
183 break;
184 } else if (FD_ISSET(fd, &fds)) {
185 drmHandleEvent(fd, &ev);
186 }
187 }
188 }
191 static const RGB colors32[] = {
192 RGB(255, 255, 255),
193 RGB(255, 0, 0),
194 RGB(255, 255, 255),
195 RGB(0, 255, 0),
196 RGB(255, 255, 255),
197 RGB(0, 0, 255),
198 RGB(255, 255, 255),
199 RGB(200, 200, 200),
200 RGB(255, 255, 255),
201 RGB(100, 100, 100),
202 RGB(255, 255, 255),
203 RGB(50, 50, 50),
204 };
206 static const uint16_t colors16[] = {
207 colors32[0].rgb565(),
208 colors32[1].rgb565(),
209 colors32[2].rgb565(),
210 colors32[3].rgb565(),
211 colors32[4].rgb565(),
212 colors32[5].rgb565(),
213 colors32[6].rgb565(),
214 colors32[7].rgb565(),
215 colors32[8].rgb565(),
216 colors32[9].rgb565(),
217 colors32[10].rgb565(),
218 colors32[11].rgb565(),
219 };
221 static void drm_draw_color_bar_rgb888(Framebuffer& buf, int old_xpos, int xpos, int width)
222 {
223 for (unsigned y = 0; y < buf.height(); ++y) {
224 RGB bcol = colors32[y * ARRAY_SIZE(colors32) / buf.height()];
225 uint32_t *line = (uint32_t*)(buf.map(0) + buf.stride(0) * y);
227 if (old_xpos >= 0) {
228 for (int x = old_xpos; x < old_xpos + width; ++x)
229 line[x] = 0;
230 }
232 for (int x = xpos; x < xpos + width; ++x)
233 line[x] = bcol.raw;
234 }
235 }
237 static void drm_draw_color_bar_rgb565(Framebuffer& buf, int old_xpos, int xpos, int width)
238 {
239 static_assert(ARRAY_SIZE(colors32) == ARRAY_SIZE(colors16), "bad colors arrays");
241 for (unsigned y = 0; y < buf.height(); ++y) {
242 uint16_t bcol = colors16[y * ARRAY_SIZE(colors16) / buf.height()];
243 uint16_t *line = (uint16_t*)(buf.map(0) + buf.stride(0) * y);
245 if (old_xpos >= 0) {
246 for (int x = old_xpos; x < old_xpos + width; ++x)
247 line[x] = 0;
248 }
250 for (int x = xpos; x < xpos + width; ++x)
251 line[x] = bcol;
252 }
253 }
255 static void drm_draw_color_bar_semiplanar_yuv(Framebuffer& buf, int old_xpos, int xpos, int width)
256 {
257 const uint8_t colors[] = {
258 0xff,
259 0x00,
260 0xff,
261 0x20,
262 0xff,
263 0x40,
264 0xff,
265 0x80,
266 0xff,
267 };
269 for (unsigned y = 0; y < buf.height(); ++y) {
270 unsigned int bcol = colors[y * ARRAY_SIZE(colors) / buf.height()];
271 uint8_t *line = (uint8_t*)(buf.map(0) + buf.stride(0) * y);
273 if (old_xpos >= 0) {
274 for (int x = old_xpos; x < old_xpos + width; ++x)
275 line[x] = 0;
276 }
278 for (int x = xpos; x < xpos + width; ++x)
279 line[x] = bcol;
280 }
281 }
283 static void draw_color_bar(Framebuffer& buf, int old_xpos, int xpos, int width)
284 {
285 switch (buf.format()) {
286 case DRM_FORMAT_NV12:
287 case DRM_FORMAT_NV21:
288 // XXX not right but gets something on the screen
289 drm_draw_color_bar_semiplanar_yuv(buf, old_xpos, xpos, width);
290 break;
292 case DRM_FORMAT_YUYV:
293 case DRM_FORMAT_UYVY:
294 // XXX not right but gets something on the screen
295 drm_draw_color_bar_rgb565(buf, old_xpos, xpos, width);
296 break;
298 case DRM_FORMAT_RGB565:
299 drm_draw_color_bar_rgb565(buf, old_xpos, xpos, width);
300 break;
302 case DRM_FORMAT_XRGB8888:
303 drm_draw_color_bar_rgb888(buf, old_xpos, xpos, width);
304 break;
306 default:
307 ASSERT(false);
308 }
309 }